Skip to content

feat(modules): add Unix domain socket transport support#259

Merged
kp2pml30 merged 2 commits intomainfrom
feat/nod-700-request-unix-socket-binding-support-in-genvm-manager
Feb 3, 2026
Merged

feat(modules): add Unix domain socket transport support#259
kp2pml30 merged 2 commits intomainfrom
feat/nod-700-request-unix-socket-binding-support-in-genvm-manager

Conversation

@dohernandez
Copy link
Member

@dohernandez dohernandez commented Feb 3, 2026

Description

Adds Unix domain socket support to GenVM manager and modules as an alternative to TCP binding.
This enables running multiple GenVM instances on the same host without port conflicts, which is
essential for multi-validator local running for zero-downtime upgrade and testing and worktree development workflows.

Changes:

  • Manager: New --socket CLI flag (mutually exclusive with --host/--port)
  • Modules: Support unix:// prefix in bind_address configuration
  • Generic stream abstraction for WebSocket handling (TCP and Unix)

Usage:

# Manager with Unix socket
genvm-modules manager --socket /tmp/genvm-manager.sock

# Module config
bind_address: unix:///tmp/genvm-llm.sock

Types of Changes

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Chore (maintenance tasks, refactoring, or non-functional changes)

Checklist

  • My code follows the code style of this project
  • I have added the necessary documentation (if appropriate)
  • I have added tests (if appropriate)
  • Lint and unit tests pass locally with my changes

Summary by CodeRabbit

  • New Features

    • HTTP server can listen on Unix domain sockets, with automatic stale-socket removal, parent-directory creation, and orderly cleanup on shutdown.
  • Chores

    • WebSocket/transport handling refactored to support multiple transport types with improved lifecycle, shutdown, and logging behavior.

WebSocket and HTTP servers can now bind to Unix sockets via
unix:// prefix or --socket flag, enabling multiple GenVM instances
on the same host without port conflicts.
@CLAassistant
Copy link

CLAassistant commented Feb 3, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ kp2pml30
❌ dohernandez
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

Adds Unix domain socket support and a new hyper dependency; refactors common WebSocket handling to be generic over transport streams (TCP/Unix) and adds a cleanup() hook on the MessageHandler trait; manager now accepts an optional Unix socket CLI argument and runs the server over a UnixListener with lifecycle cleanup.

Changes

Cohort / File(s) Summary
Dependency Addition
modules/implementation/Cargo.toml
Added hyper = "0.14" with features ["server","http1","tcp"].
Transport Abstraction & Lifecycle
modules/implementation/src/common/mod.rs
Parameterized WebSocket stream handling over generic S: AsyncRead+AsyncWrite+Unpin; added cleanup() async method to MessageHandler; introduced transport-specific entry points (loop_one, loop_one_unix), generic read/upgrade helpers, and run_loop dispatching; added Unix socket pre-bind cleanup, parent-dir creation, and cancellation-aware socket removal; improved logging and error contexts.
HTTP Server Unix Socket Support
modules/implementation/src/manager/mod.rs
Added socket: Option<String> to CLI args; implemented Unix domain socket path mode with pre-bind stale-socket removal, parent-dir creation, a UnixAcceptor to adapt tokio::net::UnixListener to Hyper, graceful shutdown integration, and post-shutdown socket cleanup; preserved existing TCP/Warp path as fallback.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Server as Hyper/Warp
    participant Transport as Transport Layer
    participant Handler as MessageHandler

    rect rgba(200,150,200,0.5)
        Note over Client,Server: TCP flow
        Client->>Server: TCP connect
        Server->>Transport: accept TCP stream
        Server->>Client: WebSocket upgrade
        Transport->>Handler: handle_stream (TCP)
        Handler->>Handler: read_hello / message loop
        Handler->>Handler: cleanup()
        Transport->>Transport: TCP connection close
    end

    rect rgba(150,200,200,0.5)
        Note over Client,Server: Unix socket flow
        Transport->>Transport: pre-bind stale socket cleanup
        Client->>Server: connect to Unix socket
        Server->>Transport: accept Unix stream (UnixAcceptor)
        Server->>Client: WebSocket upgrade
        Transport->>Handler: handle_stream (Unix)
        Handler->>Handler: read_hello / message loop
        Handler->>Handler: cleanup()
        Transport->>Transport: remove socket file on shutdown
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A socket cleaned, a listener new and spry,
Streams made generic so both roads can fly,
Handlers tidy up when the messages cease,
Unix and TCP now share one warm peace,
Hop—deploy the warren, connections release!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature being added: Unix domain socket transport support across the GenVM modules and manager.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/nod-700-request-unix-socket-binding-support-in-genvm-manager

Important

Action Needed: IP Allowlist Update

If your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:

  • 136.113.208.247/32 (new)
  • 34.170.211.100/32
  • 35.222.179.152/32

Failure to add the new IP will result in interrupted reviews.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dohernandez dohernandez requested a review from kp2pml30 February 3, 2026 10:46
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modules/implementation/src/common/mod.rs (1)

401-407: ⚠️ Potential issue | 🟡 Minor

Misleading log message on accept error.

When listener.accept() returns an Err, the log says "accepted None" which is inaccurate. The actual case is an accept error, not a closed listener.

Suggested improvement
             accepted = listener.accept() => {
                 if let Ok((stream, _)) = accepted {
                     tokio::spawn(loop_one(handler_provider.clone(), stream));
                 } else {
-                    log_info!("accepted None");
+                    log_warn!(error:? = accepted.err(); "accept failed");
                     return Ok(())
                 }
             }
🤖 Fix all issues with AI agents
In `@modules/implementation/src/common/mod.rs`:
- Around line 453-459: The accept branch in the async Unix listener incorrectly
logs "accepted None" on Err; update the listener.accept handling (the match that
currently spawns loop_one_unix(handler_provider.clone(), stream)) to capture the
Err as e and log the actual error (e) instead of "accepted None"—use the
appropriate logging macro (e.g., log_error! or log_info! with error details) and
keep the early return behavior after logging.
🧹 Nitpick comments (1)
modules/implementation/src/manager/mod.rs (1)

332-335: Potential TOCTOU when removing stale socket.

The check-then-remove pattern has a small race window where another process could create the socket between exists() and remove_file(). This is generally acceptable for local development/testing scenarios described in the PR, but be aware that in production with rapid restarts, this could inadvertently remove an active socket from a still-running process.

Consider documenting this behavior or using advisory file locking if stricter guarantees are needed in the future.

Comment on lines +453 to +459
accepted = listener.accept() => {
if let Ok((stream, _)) = accepted {
tokio::spawn(loop_one_unix(handler_provider.clone(), stream));
} else {
log_info!("accepted None");
return Ok(())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same misleading log message on accept error.

This has the same issue as the TCP version - the "accepted None" log is inaccurate when the actual case is an accept error.

Suggested improvement
                 accepted = listener.accept() => {
                     if let Ok((stream, _)) = accepted {
                         tokio::spawn(loop_one_unix(handler_provider.clone(), stream));
                     } else {
-                        log_info!("accepted None");
+                        log_warn!(error:? = accepted.err(); "accept failed");
                         return Ok(())
                     }
                 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
accepted = listener.accept() => {
if let Ok((stream, _)) = accepted {
tokio::spawn(loop_one_unix(handler_provider.clone(), stream));
} else {
log_info!("accepted None");
return Ok(())
}
accepted = listener.accept() => {
if let Ok((stream, _)) = accepted {
tokio::spawn(loop_one_unix(handler_provider.clone(), stream));
} else {
log_warn!(error:? = accepted.err(); "accept failed");
return Ok(())
}
}
🤖 Prompt for AI Agents
In `@modules/implementation/src/common/mod.rs` around lines 453 - 459, The accept
branch in the async Unix listener incorrectly logs "accepted None" on Err;
update the listener.accept handling (the match that currently spawns
loop_one_unix(handler_provider.clone(), stream)) to capture the Err as e and log
the actual error (e) instead of "accepted None"—use the appropriate logging
macro (e.g., log_error! or log_info! with error details) and keep the early
return behavior after logging.

Copy link
Member

@kp2pml30 kp2pml30 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thanks, I wanted to add it but forgot :)

@kp2pml30 kp2pml30 enabled auto-merge February 3, 2026 12:33
@kp2pml30 kp2pml30 added this pull request to the merge queue Feb 3, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modules/implementation/src/common/mod.rs (1)

401-410: ⚠️ Potential issue | 🟡 Minor

Misleading log message on TCP accept error.

When listener.accept() returns an Err, logging "accepted None" is inaccurate. The actual error should be logged for debugging.

Suggested fix
             accepted = listener.accept() => {
                 if let Ok((stream, _)) = accepted {
                     tokio::spawn(loop_one(handler_provider.clone(), stream));
                 } else {
-                    log_info!("accepted None");
+                    log_warn!(error:? = accepted.err(); "accept failed");
                     return Ok(())
                 }
             }
🧹 Nitpick comments (1)
modules/implementation/src/common/mod.rs (1)

451-472: Consider simplifying by removing unnecessary variable binding.

The result variable binding and explicit return add no value here - the async block can be awaited directly.

Suggested simplification
-    let result = async {
-        loop {
-            tokio::select! {
-                _ = cancel.chan.closed() => {
-                    log_info!("loop cancelled");
-                    return Ok(())
-                }
-                accepted = listener.accept() => {
-                    if let Ok((stream, _)) = accepted {
-                        tokio::spawn(loop_one_unix(handler_provider.clone(), stream));
-                    } else {
-                        log_info!("accepted None");
-                        return Ok(())
-                    }
-                }
+    loop {
+        tokio::select! {
+            _ = cancel.chan.closed() => {
+                log_info!("loop cancelled");
+                return Ok(())
+            }
+            accepted = listener.accept() => {
+                if let Ok((stream, _)) = accepted {
+                    tokio::spawn(loop_one_unix(handler_provider.clone(), stream));
+                } else {
+                    log_warn!(error:? = accepted.err(); "accept failed");
+                    return Ok(())
+                }
             }
         }
     }
-    .await;
-
-    result
 }

Merged via the queue into main with commit a81871e Feb 3, 2026
4 of 5 checks passed
@kp2pml30 kp2pml30 deleted the feat/nod-700-request-unix-socket-binding-support-in-genvm-manager branch February 3, 2026 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants