Do you have any links on the "dependency-graph dataflow system" that you are talking about? Sounds a little bit similar to what I'm trying to do, except at higher scale.
Well, I believe that it's almost impossible to make rust threads lightweight because every green thread needs a stack anyway. This may be fixed with some stuff like `async/await`.
But let's talk about what's wrong with threads:
1. Timeout handling is ugly: you need to account a timeout in each read and write operation. At least timeout handling makes coroutine/threaded code no better than state machine code. But actually in state machine approach I can set a deadline once and update it only when changed (note to myself: should add such an example to documentation). In Python, it's usually fixed by making another coroutine with sleep and throw an exception to the one doing I/O. It works well, but Rust will never get exceptions (I hope)
2. When you make a server that receive a request, looks in DB then responds, there is an incentive to own (create or acquire from the pool) a DB connection by each thread. This is a sad trick. The better thing when the DB connection is handled by a coroutine on its own. Because in the latter case you may pipeline multiple requests over a connection, monitor if the connection is still alive, reconnect to DB while no requests are active, or the contrary, shut down idle connections. By pipelining you may keep less number of connections to DB so make the load to the database a little bit lower. When I'm talking about DB in this paragraph, of course, I mean everything for which this application is a client. Sure you can do that in threaded code too, but it's much harder to get right. You need two threads per connection (because one reads network and the other looks at the queue and does write), you need to synchronize both sides, connection cleanup code is complex, there is more than one level of timeouts now, so on.
3. You need to avoid deadlocks. Rust takes care to avoid data races, but deadlocks are possible. And they are not always simple or reproducible, so you will have a hard time debugging them. In the single-threaded async code, you are the only user. Even if you have an async thread per processor, you are more likely to own resources instead of locking on them. You may duplicate many things for every thread. You can have more coarse-grained locks, so never hold two of them. But it's almost impossible to write lock-free threaded server.
All of the issues above are neither fixed with async/await nor with any M:N or 1:1 threading approaches.
Probably yes, it's a problem of a baggage. If you would start clean, you need two things:
1. Support full threading and one of the memory models that allows it. To have an inspiration look at Clojure, Rust, Go, Erlang (probably I don't mean any particular order).
2. Have a standard communication way between processes, like Erlang has. My favourite would be to implement SP protocol family developed as a part of nanomsg library (https://github.com/nanomsg/nanomsg/tree/master/rfc).
> Article suggests that a high performance framework is implemented
> where notification of a unavailability will be propagated "before
> real user tried to execute a request" (which would have 50% probability
> of happening if number of heartbeats per second would be equal to number
> of requests per second the service serves, ha ha).
Yes and no. Sometimes there is a dependency that is used only on 1% of requests, or even 0.1% of requests. And that's thing thats hard to track by 50x error codes, because they are really rare.
But anyway it's not "fully designed feature", just a vision of what potentially can be done. So it's not going to be a stumbling-block for implementation.
> Also from the Article we can learn that sending a 304 with content does not work as expected (!?)
Sending 304 works as expected. Passing arbitrary status code with arbitrary headers with arbitrary body from the application to a framework doesn't work as expected.
> Not only that, but there should be only one connection to database,
> through all traffic will go. Pulling that up through a network switch
> connected to a server with multiple cables, or pushing all that through
> a single TCP connection, with a foot note that advises against rewriting
> it after a few years?
Not sure I understand your question well. But note that I'm speaking about Python. We have many python processes on the box anyway. Each of them has it's own connections to the downstreams (i.e. a database).
Then if we start writing asynchronous Python code, we need to send requests from multiple asynchronous tasks from each of the python process. I argue that it's more efficient to send requests from all tasks of a single process through a single downstream connection.
> Also, everything explained there should run in a single thread,
> because surely it will be fast enough.
Sure, single I/O thread in C will outperform any python processing of that data. That's true for 99.9% use cases.
Well, for many protocols it easy. I had written (a useful subset of) mysql protocol parser in a weekend. Sure, this is in Python, so reimplement it in C is much harder, still not years or so. Many protocols: mongodb, redis, memcached, beanstalk, etc, are much simpler.
There are protocols that take months and years, but they are not so ubiquitous (with the obvious exception of HTTP, which is really complex and ubiquitous). So they may be developed after basic tools are in place.