Summary
setup_signal_handlers() calls loop.add_signal_handler(), which is not implemented on Windows event loops. run_daemon calls it unconditionally, so the daemon dies with NotImplementedError immediately after subsystem init.
Still present on main @ 45b0ea0: runner_maintenance.py#L730-L731.
Traceback
File "...\gobby\runner_lifecycle.py", line 114, in run_daemon
setup_signal_handlers(
lambda: setattr(runner, "_shutdown_requested", True),
shutdown_intent_callback=lambda intent: setattr(runner, "_shutdown_intent", intent),
)
File "...\gobby\runner_maintenance.py", line 717, in setup_signal_handlers
loop.add_signal_handler(sig, _make_handler(sig))
File "...\Lib\asyncio\events.py", line 599, in add_signal_handler
raise NotImplementedError
NotImplementedError
Logged as Fatal error by runner_lifecycle.run_daemon; gobby start reports Health check failed.
Reproduce
On Windows, with the fcntl import blocker patched (filed separately), run gobby start.
Root cause
asyncio.ProactorEventLoop / SelectorEventLoop on Windows do not implement add_signal_handler — it is documented as Unix-only. The loop over (SIGTERM, SIGINT) has no platform guard.
Suggested fix
Fall back to signal.signal and marshal into the loop, which gives the same graceful-shutdown behaviour on Windows:
for sig in (signal.SIGTERM, signal.SIGINT):
- loop.add_signal_handler(sig, _make_handler(sig))
+ handler = _make_handler(sig)
+ try:
+ loop.add_signal_handler(sig, handler)
+ except NotImplementedError: # Windows: event loops lack signal handlers
+ signal.signal(sig, lambda _s, _f, _h=handler: loop.call_soon_threadsafe(_h))
With this applied the daemon starts and stays up on Windows.
Note
This is the second of two sequential Windows blockers; the first is the unguarded fcntl/termios import in agents/tmux/pty_bridge.py, filed as #26. Both are needed to reach a running daemon.
Environment
- gobby 0.4.6 (installed via
uv tool install)
- Python 3.13 (CPython, windows-x86_64)
- Windows 11 Pro 10.0.26220
Summary
setup_signal_handlers()callsloop.add_signal_handler(), which is not implemented on Windows event loops.run_daemoncalls it unconditionally, so the daemon dies withNotImplementedErrorimmediately after subsystem init.Still present on
main@45b0ea0:runner_maintenance.py#L730-L731.Traceback
Logged as
Fatal errorbyrunner_lifecycle.run_daemon;gobby startreportsHealth check failed.Reproduce
On Windows, with the
fcntlimport blocker patched (filed separately), rungobby start.Root cause
asyncio.ProactorEventLoop/SelectorEventLoopon Windows do not implementadd_signal_handler— it is documented as Unix-only. The loop over(SIGTERM, SIGINT)has no platform guard.Suggested fix
Fall back to
signal.signaland marshal into the loop, which gives the same graceful-shutdown behaviour on Windows:With this applied the daemon starts and stays up on Windows.
Note
This is the second of two sequential Windows blockers; the first is the unguarded
fcntl/termiosimport inagents/tmux/pty_bridge.py, filed as #26. Both are needed to reach a running daemon.Environment
uv tool install)