Summary
The native listener constructs @http.Server(addr) without passing reuse_addr:
Mocket 0.8.0 pins moonbitlang/async@0.21.0. In that version:
Therefore Mocket does not enable SO_REUSEADDR on POSIX listeners. During rapid development restarts, sockets left in TIME_WAIT can make the new process report that the port is still occupied even after the previous listener has exited.
Observed behavior
After sending traffic, stopping the previous process, and immediately starting the native Mocket server on the same 127.0.0.1:49400 address:
mocket: failed to listen on 127.0.0.1:49400:
OSError("@socket.TcpServer::new(): Address already in use")
lsof showed no process listening on that port. A second immediate attempt produced the same error. Because listen_ffi catches the bind error and returns, the process also exits successfully instead of reporting failure to its caller.
This is OS-, address-, and timing-dependent: a native-to-native control restart succeeded in one macOS run. That does not change the configuration issue; the async socket documentation describes TIME_WAIT rebinding as the purpose of reuse_addr.
Expected behavior
Enable address reuse by default in Mocket's native listener by passing reuse_addr=true when constructing the HTTP server:
let server = @http.Server(addr, reuse_addr=true)
This should be the primary fix so existing applications get reliable rapid restarts without additional configuration. If Mocket also wants to expose this setting publicly, it should be an opt-out whose default remains true, rather than an option that leaves the current false behavior unchanged.
Document the BSD/macOS wildcard/specific-address caveat described by moonbitlang/async. Bind failures should also propagate as checked errors rather than being printed and converted to a successful return, so supervisors and development tools can react correctly.
Summary
The native listener constructs
@http.Server(addr)without passingreuse_addr:Mocket 0.8.0 pins
moonbitlang/async@0.21.0. In that version:@http.Serverforwardsreuse_addrtoTcpServerTcpServerdefaultsreuse_addrtofalseTherefore Mocket does not enable
SO_REUSEADDRon POSIX listeners. During rapid development restarts, sockets left inTIME_WAITcan make the new process report that the port is still occupied even after the previous listener has exited.Observed behavior
After sending traffic, stopping the previous process, and immediately starting the native Mocket server on the same
127.0.0.1:49400address:lsofshowed no process listening on that port. A second immediate attempt produced the same error. Becauselisten_fficatches the bind error and returns, the process also exits successfully instead of reporting failure to its caller.This is OS-, address-, and timing-dependent: a native-to-native control restart succeeded in one macOS run. That does not change the configuration issue; the async socket documentation describes
TIME_WAITrebinding as the purpose ofreuse_addr.Expected behavior
Enable address reuse by default in Mocket's native listener by passing
reuse_addr=truewhen constructing the HTTP server:This should be the primary fix so existing applications get reliable rapid restarts without additional configuration. If Mocket also wants to expose this setting publicly, it should be an opt-out whose default remains
true, rather than an option that leaves the currentfalsebehavior unchanged.Document the BSD/macOS wildcard/specific-address caveat described by
moonbitlang/async. Bind failures should also propagate as checked errors rather than being printed and converted to a successful return, so supervisors and development tools can react correctly.