Files
alknet/docs/architecture/questions/061-multi-owner-shutdown-coordination.md
T
glm-5.2 81bde6f28f docs(arch): endpoint as pure accept-loop runner + acme-tls/1 guard relocation (ADR-083, OQ-60/61)
ADR-083: AlknetEndpoint becomes a pure accept-loop runner with a public
dispatch method. Transport construction moves out of the endpoint — the
assembly layer reads StaticConfig, builds transports from
TlsServerConfig(s), and hands pre-built quinn/iroh endpoints to the
endpoint via with_quinn/with_iroh. TCP+TLS dispatch is first-class (same
dispatch path as quinn/iroh); ADR-010 Amendment 1's duplicated-dispatch
workaround is retired. StaticConfig stays in core as the assembly-layer
config; the endpoint takes only drain_timeout.

The acme-tls/1 guard moves from dispatch_quinn to the shared dispatch
method — ACME TLS-ALPN-01 challenges arrive over TCP (CAs validate via
TCP to port 443, not QUIC), so the guard's quinn-specific location was a
latent bug once TCP+TLS exists. The guard is transport-agnostic; the
rationale (no handler, silent close) is unchanged. ADR-027 §5 amended.

OQ-60: where build_iroh_endpoint lives (assembly layer / alknet-tls
helper / transport module). build_quinn_server_config_from_rustls is
decided — it moves to alknet-tls as for_quinn() per ADR-082; only
build_iroh_endpoint is genuinely undecided.

OQ-61: multi-owner shutdown coordination. Boundary committed (endpoint
owns dispatched handlers; assembly layer owns spawned accept loops);
mechanism open.

ADR-082 amended: drops the Arc<TlsServerConfig> endpoint signature
(superseded by ADR-083); keeps its scope as the alknet-tls crate's
TlsServerConfig + accessors.

Review: zero critical issues, five warnings fixed (build_iroh_endpoint
destination contradiction, undeclared shutdown_sender, missing ADR-027
amendment marker, underspecified dispatch no-match behavior, stale
door-type timing clause).
2026-07-14 07:59:04 +00:00

2.1 KiB

OQ-61: Multi-Owner Shutdown Coordination

  • Origin: docs/architecture/decisions/083-endpoint-as-accept-loop-runner.md (the endpoint owns dispatched handlers; the assembly layer owns spawned accept loops — coordination between them on shutdown is unspecified).

  • Status: open

  • Door type: two-way (the coordination mechanism is an implementation detail; the ownership boundary — endpoint owns dispatched handlers, assembly layer owns spawned accept loops — is the one-way part, committed in ADR-083)

  • Priority: medium (matters for clean hub shutdown; doesn't block the endpoint-shape decision or the TLS extraction)

  • Blocked on: nothing structural. The question is which coordination primitive (shared shutdown_sender, separate channel, drain semantics) — a design choice, not a missing capability.

  • Resolution: Not yet decided. The boundary is clear:

    • The endpoint owns shutdown of dispatched handlers (it spawned them via tokio::spawn in dispatch).
    • The assembly layer owns shutdown of the accept loops it spawned (the TCP+TLS listeners).

    The open question is the coordination mechanism:

    • Does the assembly layer use the endpoint's shutdown_sender() to signal the TCP+TLS loops, or a separate channel?
    • Does endpoint.shutdown() drain in-flight dispatched handlers (including those from TCP+TLS loops), or only the quinn/iroh ones it spawned via run()?
    • What happens to in-flight dispatch calls after the endpoint is shut down — are they rejected, or do they complete?

    A likely shape: the assembly layer uses the endpoint's shutdown_sender() for all its accept loops (one signal, all loops stop accepting); the endpoint's shutdown() drains all dispatched handlers regardless of which transport spawned them (the endpoint owns them all once dispatch is called). But this needs to be written down and verified against the drain semantics.

  • Cross-references: ADR-083 (endpoint refactor — ownership boundary), ADR-010 (original shutdown design — single-owner, the simpler case being generalized)