Skip to content

[client] Refactor/relay conn container#5271

Merged
pappz merged 4 commits intomainfrom
refactor/relay-conn-container
Feb 13, 2026
Merged

[client] Refactor/relay conn container#5271
pappz merged 4 commits intomainfrom
refactor/relay-conn-container

Conversation

@pappz
Copy link
Copy Markdown
Collaborator

@pappz pappz commented Feb 6, 2026

Refactor/relay conn container from Client

Conn previously held a direct *Client pointer and called client methods (writeTo, closeConn, LocalAddr) directly, creating a tight bidirectional coupling. The message channel was also created externally in OpenConn and shared between Conn and connContainer with unclear ownership.

Now connContainer fully owns the lifecycle of both the channel and the Conn it wraps:

  • connContainer creates the channel (sized by connChannelSize const) and the Conn internally via newConnContainer
  • connContainer feeds messages into the channel (writeMsg), closes and drains it on shutdown (close)
  • Conn reads from the channel (Read) but never closes it

Conn is decoupled from *Client by replacing the *Client field with three function closures (writeFn, closeFn, localAddrFn) that are wired by newConnContainer at construction time. Write, Close, and LocalAddr delegate to these closures. This removes the direct dependency while keeping the identity-check logic: writeTo and closeConn now compare connContainer pointers instead of Conn pointers to verify the caller is the current active connection for that peer.

Describe your changes

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Summary by CodeRabbit

  • Refactor
    • Improved internal connection management architecture in the relay client to enhance code maintainability and reliability.

pappz added 3 commits February 5, 2026 13:49
connection establishment

Reorder operations in OpenConn to register the connection before
waiting for peer availability. This ensures:

- Connection is ready to receive messages before peer subscription
completes
- Transport messages and onconnected events maintain proper ordering
- No messages are lost during the connection establishment window
- Concurrent OpenConn calls cannot create duplicate connections

If peer availability check fails, the pre-registered connection is
properly cleaned up.
Ensure relay connections are properly cleaned up when the service is not running by verifying `serviceIsRunning` and removing stale entries from `c.conns` to prevent unintended behaviors.
…from Client

Conn previously held a direct *Client pointer and called client methods
(writeTo, closeConn, LocalAddr) directly, creating a tight bidirectional
coupling. The message channel was also created externally in OpenConn and
shared between Conn and connContainer with unclear ownership.

Now connContainer fully owns the lifecycle of both the channel and the
Conn it wraps:
- connContainer creates the channel (sized by connChannelSize const)
  and the Conn internally via newConnContainer
- connContainer feeds messages into the channel (writeMsg), closes and
  drains it on shutdown (close)
- Conn reads from the channel (Read) but never closes it

Conn is decoupled from *Client by replacing the *Client field with
three function closures (writeFn, closeFn, localAddrFn) that are wired
by newConnContainer at construction time. Write, Close, and LocalAddr
delegate to these closures. This removes the direct dependency while
keeping the identity-check logic: writeTo and closeConn now compare
connContainer pointers instead of Conn pointers to verify the caller
is the current active connection for that peer.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

The PR refactors relay client connection handling by introducing a connContainer abstraction that encapsulates Conn construction and lifecycle management. This replaces direct client references in Conn with dependency-injected function fields, improving separation of concerns between the client and connection layers.

Changes

Cohort / File(s) Summary
Connection Container Abstraction
shared/relay/client/client.go
Introduces connContainer with internal Conn construction and wiring. Updates OpenConn to create containers, refactors writeTo and closeConn to accept container references instead of direct Conn instances. Adds netConn() accessor method.
Connection Dependency Injection
shared/relay/client/conn.go
Removes public client field from Conn and replaces with injected function fields (writeFn, closeFn, localAddrFn). Updates Write, Read, Close, and LocalAddr methods to delegate through functions. Adds placeholder deadline methods and removes NewConn constructor.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • lixmal

Poem

A container now holds what once was bare,
With functions injected with utmost care.
The client and conn dance in new ways,
Through dependency fields, connection displays. 🐰✨

🚥 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
Title check ✅ Passed The title accurately summarizes the main change: refactoring the relay connection container to improve decoupling and ownership clarity.
Description check ✅ Passed The description comprehensively explains the refactoring rationale, changes made, and documentation decision. All template sections are addressed.

✏️ 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 refactor/relay-conn-container

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.

@pappz pappz requested a review from lixmal February 6, 2026 16:44
Base automatically changed from fix/relay-msg-orders to main February 9, 2026 10:34
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
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.

Caution

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

⚠️ Outside diff range comments (1)
shared/relay/client/conn.go (1)

57-60: ⚠️ Potential issue | 🟡 Minor

Copy-paste bug in panic message: says "SetReadDeadline" instead of "SetWriteDeadline".

Line 59 panic string is incorrect — it should reference SetWriteDeadline.

Proposed fix
 func (c *Conn) SetWriteDeadline(t time.Time) error {
 	//TODO implement me
-	panic("SetReadDeadline is not implemented")
+	panic("SetWriteDeadline is not implemented")
 }
🧹 Nitpick comments (2)
shared/relay/client/conn.go (1)

24-33: Read: silent data truncation when b is smaller than m.Payload.

If the caller provides a buffer smaller than the incoming payload, copy will silently truncate data with no indication to the caller. This is a pre-existing concern (not introduced by this PR), but worth noting: callers must ensure buffer sizes match the expected MTU. Consider returning io.ErrShortBuffer when len(b) < len(m.Payload) in a follow-up.

shared/relay/client/client.go (1)

21-21: Consider documenting the rationale for connChannelSize = 100.

A brief comment explaining why 100 was chosen (e.g., based on expected throughput, backpressure tolerance) would help future maintainers understand the trade-off between memory usage and message drop likelihood (given the default drop in writeMsg).

@pappz pappz merged commit edce11b into main Feb 13, 2026
38 of 39 checks passed
@pappz pappz deleted the refactor/relay-conn-container branch February 13, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants