tomaka / rouille

Web framework in Rust
Apache License 2.0
1.12k stars 106 forks source link

Non-blocking WebSocket polling #140

Closed randomPoison closed 2 years ago

randomPoison commented 7 years ago

Related to #137, would it be possible to have a non-blocking variant of WebSocket::next? The idea would be the same as Receiver<T>::try_recv, it returns the next message if there is one ready, but returns without blocking if there are none. Without this functionality, it seems like it isn't possible to do something like have a thread wait for either a WebSocket or another channel.

I took a brief look at the implementation of WebSocket::next and it looks like its the underlying Box<ReadWrite>::read implementation that blocks waiting for data from the socket. Given that rouille is built on tiny_http, would it even be possible to implement a non-blocking read from the socket? Also, is it possible that I'm completely off-base in thinking that it's not possible to wait on both a WebSocket and another channel?

tomaka commented 7 years ago

would it even be possible to implement a non-blocking read from the socket?

The answer is probably no.

randomPoison commented 7 years ago

Ah, that's a shame. Do you have a sense of whether that would be because of how tiny-http is implemented, or because of how the underlying OS handles sockets at a fundamental level? I'm not personally experienced working with sockets in general.

mleonhard commented 3 years ago

I need this.

bradfier commented 3 years ago

I need this.

I haven't had time to poke around in the WebSockets code other than to do some refactoring on the byte order bit twiddling. As a result I don't have a view on how complex (or even possible) this will be to implement.

Of course things have changed since 2017 when Tomaka looked, so it's possible it can be done now.

I would accept patches to enable a non-blocking call if you're interested in implementing it.

gwbres commented 2 years ago

@randomPoison, @bradfier, try_recv() and recv_with_timeout() are natively supported, since the websocket stream is a channel https://doc.rust-lang.org/std/sync/mpsc/struct.Receiver.html

randomPoison commented 2 years ago

Okay, thanks for the follow-up. I'm no longer using rouille so I will close this issue. Feel free to reopen if needed though!

mleonhard commented 2 years ago

@gwbres I think there's a little mixup. This issue is about polling for new messages. When setting up a new connection, you call rouille::websocket::start and get a std::sync::mpsc::Receiver<Websocket> struct. You can poll that Receiver and get the rouille::websocket::Websocket struct. But then there is no way to poll the Websocket struct for new messages sent by the remote client. This means that a server that wants to receive websocket messages must use a thread per connection. That scales poorly.

I also stopped using Rouille because of this and other scaling problems. I wrote a new webserver that should scale better: beatrice.

gwbres commented 2 years ago

@mleonhard that is totally correct, this approach requires one thread per connection

bradfier commented 2 years ago

Any modern server should easily handle thousands of threads if you need one per connection, if your requirements are an order of magnitude or two above that, then an Async framework will definitely be the way to go instead of using Rouille and it's synchronous approach.