Skip to content

Commit 455aedd

Browse files
rustyconoverclaude
andcommitted
Fix Worker.run()'s --unix Windows dispatch: named pipe, not AF_UNIX
vgi.worker.Worker's _run() classmethod (the CLI entry point every Worker subclass's `main()` goes through) called serve_unix() unconditionally for --unix, regardless of platform - crashing outright on Windows: AttributeError: module 'socket' has no attribute 'AF_UNIX' (from vgi_rpc.rpc._transport.serve_unix's own socket.socket(socket.AF_UNIX, ...) call, itself correct - AF_UNIX genuinely doesn't exist in this code path on Windows, since CPython has no socket.AF_UNIX there in general use). This is a real, live bug, not theoretical: found via vgi-sqlite's own Windows CI, whose launch: locations pass --unix a \\.\pipe\...- formatted named pipe name on Windows (per docs/launcher-protocol.md's own "Platform: Windows" section) - every Worker subclass fixture (vgi-fixture-simple-writable-worker, vgi-sqlite's own row_transform fixture) crashed near-instantly on startup as a result, while vgi._test_fixtures.worker (used by the main vgi-fixture-worker, built directly against vgi_rpc.rpc.run_server rather than this classmethod) worked fine - because run_server (vgi_rpc/rpc/__init__.py) already has the correct sys.platform == "win32" dispatch to serve_named_pipe. This classmethod is a separate, parallel serving path (it also handles Sentry/OTel setup and cls-specific worker construction) that never got the same fix when run_server's was added, so it silently diverged. Fixed by mirroring run_server's own dispatch exactly: sys.platform == "win32" calls serve_named_pipe(server, unix, ...) and emits "PIPE:<name>" on stdout; every other platform keeps the existing serve_unix(server, os.path.abspath(unix), ...) / "UNIX:<path>" behavior unchanged. Not touched (a separate, narrower gap, not exercised by any of the Windows CI failures this fix addresses): vgi/transactor/server.py's own serve_unix() call, used only by the fuller `writable` fixture's transactor subprocess (needs the optional transactor extra) - no test currently reaches it on Windows. Verified on a real Windows/MSVC box (europa): manually invoking vgi-fixture-simple-writable-worker --unix \\.\pipe\... now correctly emits "PIPE:\\.\pipe\..." instead of crashing. vgi-sqlite's full Windows integration suite (test/integration, driving the built extension via launch: locations for all three fixture workers) re-run clean after this fix: 52 passed, 7 skipped (HTTP transport, needs the http extra) - up from 17 failures (all in the simple_writable- and row_transform-backed test files) before it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSuWTdDRYPk2TziYXR4GVV
1 parent 430cbb3 commit 455aedd

1 file changed

Lines changed: 44 additions & 15 deletions

File tree

‎vgi/worker.py‎

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,10 +1613,23 @@ def _run(
16131613
max_externalized_response_bytes=max_externalized_response_bytes,
16141614
)
16151615
elif unix is not None:
1616-
# AF_UNIX launcher path. Bind to the requested socket,
1617-
# print UNIX:<abs_path> on stdout, idle-shutdown after
1618-
# idle_timeout seconds.
1619-
from vgi_rpc.rpc import serve_unix
1616+
# AF_UNIX launcher path on POSIX; Windows has no
1617+
# socket.AF_UNIX in this code path, so --unix there
1618+
# carries a named-pipe name (\\.\pipe\...) instead - the
1619+
# launcher constructs whichever one is appropriate for the
1620+
# platform it's running on. Mirrors vgi_rpc.rpc.run_server's
1621+
# own platform dispatch (vgi_rpc/rpc/__init__.py) exactly -
1622+
# this classmethod has its own, separate serving path (not
1623+
# a call to run_server) because it also handles Sentry/OTel
1624+
# setup and cls-specific worker construction, but the
1625+
# transport-level platform choice must stay identical
1626+
# between the two, or a worker built against this
1627+
# classmethod (e.g. any vgi.worker.Worker subclass) crashes
1628+
# on Windows with "AttributeError: module 'socket' has no
1629+
# attribute 'AF_UNIX'" while one built directly against
1630+
# run_server works fine - confirmed as a real, live bug
1631+
# this way, not theoretical.
1632+
from vgi_rpc.rpc import serve_named_pipe, serve_unix
16201633

16211634
from vgi.serve import _maybe_init_sentry, _resolve_otel_config
16221635

@@ -1629,20 +1642,36 @@ def _run(
16291642

16301643
instrument_server(server, otel_config)
16311644
worker._vgi_tracer = VgiTracer.create(otel_config)
1632-
abs_path = os.path.abspath(unix)
16331645
effective_idle = idle_timeout if idle_timeout > 0 else None
16341646

1635-
def _emit(bound: str) -> None:
1636-
print(f"UNIX:{bound}", flush=True)
1647+
if sys.platform == "win32":
1648+
pipe_name = unix
16371649

1638-
serve_unix(
1639-
server,
1640-
abs_path,
1641-
threaded=True,
1642-
max_connections=max_connections,
1643-
idle_timeout=effective_idle,
1644-
on_bound=_emit,
1645-
)
1650+
def _emit(bound: str) -> None:
1651+
print(f"PIPE:{bound}", flush=True)
1652+
1653+
serve_named_pipe(
1654+
server,
1655+
pipe_name,
1656+
threaded=True,
1657+
max_connections=max_connections,
1658+
idle_timeout=effective_idle,
1659+
on_bound=_emit,
1660+
)
1661+
else:
1662+
abs_path = os.path.abspath(unix)
1663+
1664+
def _emit(bound: str) -> None:
1665+
print(f"UNIX:{bound}", flush=True)
1666+
1667+
serve_unix(
1668+
server,
1669+
abs_path,
1670+
threaded=True,
1671+
max_connections=max_connections,
1672+
idle_timeout=effective_idle,
1673+
on_bound=_emit,
1674+
)
16461675
elif tcp is not None:
16471676
# TCP launcher path. Bind to [HOST:]PORT, print
16481677
# TCP:<host>:<port> on stdout (mirrors run_server's

0 commit comments

Comments
 (0)