simolus3 opened PR #14320 from simolus3:serve-unix-sockets to bytecodealliance:main:
This changes
wasmtime serveto add support for
- Listening on multiple sockets:
wasmtime servecurrently serves http requests from a single TCP server. This adds support for multiple server sockets, which is useful to e.g. listen for both ipv4 and ipv6 connections, e.g. withwasmtime serve app.wasm --addr 127.0.0.1:8080 --addr [::1]:8080. Multiple sockets can also be inherited via--systemd-listenfd.- Unix domain sockets. In setups where
wasmtime serveruns behind a reverse proxy, using unix sockets instead of TCP is simpler and likely faster. With this PR, unix sockets can be inherited via--systemd-listenfd. This avoids having to parse both file paths and ip addresses from parameters, but maybe it makes sense to do that as well.Support for multiple sockets is implemented by spawning one task per socket that otherwise runs the existing request loop. To avoid concurrency for debugging setup, that still runs outside of a concurrent task (and thus only supports a single socket).
simolus3 requested dicej for a review on PR #14320.
simolus3 requested wasmtime-core-reviewers for a review on PR #14320.
simolus3 updated PR #14320.
:thumbs_up: dicej submitted PR review:
Thanks, @simolus3!
dicej added PR #14320 wasmtime serve: Support multiple sockets, unix sockets to the merge queue.
github-merge-queue[bot] removed PR #14320 wasmtime serve: Support multiple sockets, unix sockets from the merge queue.
@simolus3 Looks like the Windows builds are failing due to ungated Unix-isms.
simolus3 updated PR #14320.
simolus3 commented on PR #14320:
I didn't know we couldn't do
cfginpin-project-lite, I'm now using this workaround, I also had to markStdSocketServer::Inetas unix-only since it's not constructed on Windows builds, leading to a warning. It's a hard for me to test locally since I don't have access to Windows, but I hope it works now.
simolus3 edited a comment on PR #14320:
I didn't know we couldn't do
cfginpin-project-lite, I'm now using this workaround. I also had to markStdSocketServer::Inetas unix-only since it's not constructed on Windows builds, leading to a warning. It's a hard for me to test locally since I don't have access to Windows, but I hope it works now.
simolus3 updated PR #14320.
simolus3 updated PR #14320.
simolus3 updated PR #14320.
simolus3 commented on PR #14320:
@dicej Could you take another look please?
:thumbs_up: dicej submitted PR review:
LGTM; just one comment inline.
:speech_balloon: dicej created PR review comment:
This line appears to be redundant given the
#[cfg(unix)]on thepin_project!.
simolus3 updated PR #14320.
dicej added PR #14320 wasmtime serve: Support multiple sockets, unix sockets to the merge queue.
:check: dicej merged PR #14320.
dicej removed PR #14320 wasmtime serve: Support multiple sockets, unix sockets from the merge queue.
alexcrichton commented on PR #14320:
Is there precedent in other tooling for opening multiple sockets with multiple
--addr-style arguments? I'd naively have expected one socket to be bound to multiple addresses, but I'm also not familiar with any tool that accepts multiple arguments.
simolus3 commented on PR #14320:
I'd naively have expected one socket to be bound to multiple addresses
Outside of a
0.0.0.0dualstack address, is that possible?TcpListener::bindsays "If addr yields multiple addresses, bind will be attempted with each of the addresses until one succeeds and returns the listener". My idea was that we might want to support passing paths for unix sockets to listen on in the future as well.So this mostly seemed like the smallest change to get this to work, if this usage seems odd I can open another PR to change it. I didn't base this on any particular convention, but I found other tools with similar patterns, the docker daemon supports
dockerd -H unix:///var/run/docker.sock -H tcp://192.168.59.106 -H tcp://10.10.10.2for example. dnsmasq and gunicorn also support the same pattern with multiple--listen-addressand--bindarguments.
simolus3 edited a comment on PR #14320:
I'd naively have expected one socket to be bound to multiple addresses
Outside of a
0.0.0.0dualstack address, is that possible?TcpListener::bindsays "If addr yields multiple addresses, bind will be attempted with each of the addresses until one succeeds and returns the listener". My idea was that we might want to support passing paths for unix sockets to listen on in the future as well.Is there precedent in other tooling for opening multiple sockets with multiple
--addr-style arguments?This mostly seemed like the smallest change to get this to work, if this usage seems odd I can open another PR to change it. I didn't base this on any particular convention, but I found other tools with similar patterns, the docker daemon supports
dockerd -H unix:///var/run/docker.sock -H tcp://192.168.59.106 -H tcp://10.10.10.2for example. dnsmasq and gunicorn also support the same pattern with multiple--listen-addressand--bindarguments.
alexcrichton commented on PR #14320:
I'm mostly just vaguely aware that binding multiple addresses is a thing, but if that's only intended for niche scenarios then it seems inapplicable here. If there's precedent elsewhere though that seems fine.
Looking at this change though, this looks like it breaks the
--shutdown-addroption. The synchronization there was only workable for one connection as opposed to multiple, so the shutdown address only works for a single listener not multiple. It also looks like there are no tests for--addrbeing specified multiple times, only the inherit-multiple path.
simolus3 commented on PR #14320:
I think
--shutdown-addrshould still work becausenotify_waiters()notifies all tasks? The existing test also relies on that, but I'll look into it and will add a test specifying multiple addresses.
alexcrichton commented on PR #14320:
Looking again I think I manage to always confuse myself with tokio's
Notifystructure... I think there's definitely a bug wherenotify_waitersdoes nothing if there aren't actually any waiters (nothing is buffered). That's preexisting from before this, however, because if something wasn't actively waiting on.notified()thennotify_waitersis a noop, so between when a connection is accepted and the task for the connection is spawned if anotify_waitershappens then nothing actually breaks out of the loop. I'll work on fixing this since it's a preexisting issue, but if you're willing to add a test with multiple--addroptions that'd be appreciated yeah
Last updated: Oct 11 2026 at 02:20 UTC