Skip to content

Transport lifecycle hardening: explicit quiescence boundary and session state - #2

Merged
Snowy117 merged 3 commits into
masterfrom
feat/transport-lifecycle
Sep 20, 2026
Merged

Snowy117 merged 3 commits into
masterfrom
feat/transport-lifecycle

Conversation

@Snowy117

Copy link
Copy Markdown
Owner

Summary

Makes the TCP/UDP transport teardown boundary and session state explicit, replacing implicit unowned background work and implicit state.

Task: 09-20-transport-lifecycle (archived under .trellis/tasks/archive/2026-09/).

Ownership (R6)

  • DurableCaptureBundle is the sole owner of the native buffer pools and the single shared SetupExecutor.
  • Coordinators take them as required non-null ctor deps and never dispose injected collaborators; _ownsX flags and create-if-null branches removed; TcpProxyCoordinator.DisposeAsync is single-flight.

TCP quiescence (R1/R2)

  • TcpProxyRelay.DisposeAsync awaits Completion (fault observed and swallowed).
  • The accept loop awaits its terminal relay observation + redundant-accept drain and owns the session lifetime, so the store's await session.AcceptLoop is a real quiescence wait; the lifetime CTS is disposed after its last reader.
  • Attach failure tears the session down outside the setup try; RegisterSessionAsync releases the claimed listener/alias/token on a partial failure; the setup-failure cooldown is written inside the store inflight section.
  • Corrected the earlier assumption that the two TcpRelayFaultObserver.Observe sites were duplicates — they are distinct discard paths.

UDP lifecycle (R3/R4/R5)

  • Per-session linked lifetime CTS: idle expiry is now a normal teardown and no longer fabricates a _receiveFailure.
  • UdpSessionState / UdpTeardownReason make the state machine and the teardown reason explicit; only SetupFailure arms the setup cooldown.
  • SendSpanAsync returns ValueTask<bool>; a send against an expiring/faulted session is a counted, rate-limited fail-closed drop instead of an IOException reaching the dispatcher; the sender never removes the slot.
  • The coordinator drains in-flight receive-failure teardowns on dispose.

Gates

Gate Result
dotnet format WinForward.slnx --severity info --verify-no-changes --no-restore exit 0, empty output
dotnet build WinForward.slnx -c Release 0 warnings
dotnet test WinForward.slnx -c Release 744 / 744
jb inspectcode -f=Xml -e=HINT 0 issues

Spec

Updated tcp-local-redirect.md, udp-relay.md, error-handling.md, quality-guidelines.md.

Notes

  • TcpProxyCoordinator.cs is at 395/400 effective lines — the next change should plan a split.
  • GcSoakScenario.cs remains over the 400 effective-line limit (pre-existing).
  • Deferred follow-up (not tasked): structured concurrency (TaskScope) + lifetime analyzers.

TCP/UDP teardown relied on implicit, unowned background work and implicit
session state; make both explicit.

Ownership: DurableCaptureBundle owns the native pools and the single shared
SetupExecutor; the coordinators take them as required ctor deps and never
dispose injected collaborators.

TCP: relay DisposeAsync awaits Completion (fault observed and swallowed); the
acceptor awaits its terminal relay observation and owns the session lifetime,
so the store's "await AcceptLoop" is a real quiescence wait; attach failure now
tears the session down outside the setup try; RegisterSession releases the
claimed listener/alias/token on a construction fault; the setup-failure
cooldown is written inside the store inflight section.

UDP: per-session linked lifetime CTS (idle expiry no longer fabricates a
receive failure); UdpSessionState/UdpTeardownReason enums; SendSpanAsync
returns bool and drops fail-closed (counted, rate-limited) instead of throwing;
the coordinator drains in-flight failure teardowns on dispose.

Gates: format clean, Release build 0 warnings, 744 tests green, jb 0 issues.
@Snowy117
Snowy117 merged commit 8d7e869 into master Sep 20, 2026
3 checks passed
@Snowy117
Snowy117 deleted the feat/transport-lifecycle branch September 20, 2026 13:55
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.

1 participant