add reuse_port option to enable SO_REUSEPORT on TcpServer - #525
Conversation
Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
|
In fact
(1) sounds bad to me. Currently BTW it would be very helpful if you could share your use case that requires |
…ame to reuse_port_lb Per review: SO_REUSEPORT only load-balances connections on Linux; on the BSDs and MacOS which socket accepts a connection is unspecified. Enable it only on Linux, rename the option to reuse_port_lb to signal the load-balancing intent, and document the exec-based multi-worker use case it serves. The test now runs only on Linux, where the shared-port bind is meaningful. Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
|
Thanks, that's a fair distinction. I went with your option (2). The use case: I'm building a small ASGI/HTTP server on top of Given that, I've reworked the PR to your option (2):
Happy to pick a different name if you'd prefer something else — |
| // `reuse_port_lb` only takes effect on Linux (that is where SO_REUSEPORT | ||
| // load-balances), so the shared-port bind below is exercised there; the test is | ||
| // compiled out elsewhere. | ||
| #cfg(platform="linux") |
There was a problem hiding this comment.
Unfortunately, #cfg(platform) only support windows currently. You can add a runtime guard @event_loot.platform is Linux else { return } check to the beginning of the test instead.
| let server2 = @socket.TcpServer(addr, reuse_port_lb=true) | ||
| // Close the first server so the exchange below deterministically goes | ||
| // to server2, which is now the only socket listening on that port. | ||
| server1.close() |
There was a problem hiding this comment.
Let's try if we can have a test with two servers listening concurrently to observe the load balancing behavior. To avoid unstable test result, we can only demand both servers can receive new connections, without asserting the order they receive new connections
TcpServerexposesreuse_addr(SO_REUSEADDR) but has no way to set SO_REUSEPORT. SO_REUSEPORT lets several sockets, typically one per worker process, bind the same address at the same time, with the kernel spreading incoming connections across them. It's the usual basis for a prefork server (nginx'sreuseport, the multi-worker mode of uvicorn/gunicorn), and SO_REUSEADDR alone can't express it.This adds a
reuse_port? : Bool = falseparameter toTcpServer, mirroring the existingreuse_addrexactly:socket.c:moonbitlang_async_allow_reuse_port, guarded by#ifdef SO_REUSEPORTso it compiles to a no-op where the option doesn't exist.ffi.mbt/ffi.wasm.mbt: the matching binding; the wasm side is a no-op, since wasm has no multi-process model.tcp.mbt: the option is applied beforebind, and gated off on Windows just likereuse_addr.SO_REUSEPORTis available on Linux (3.9+), the BSDs and macOS; on Windows and wasm the option is ignored.The added native-only test binds two servers to the same port at once, which only succeeds with SO_REUSEPORT, and checks that connections are served across both.