Skip to content

Build an independent STOMP 1.2 core with compatible facade adapters - #205

Draft
vrslev wants to merge 13 commits into
mainfrom
feature/session-core
Draft

vrslev wants to merge 13 commits into
mainfrom
feature/session-core

Conversation

@vrslev

@vrslev vrslev commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator

Agent:

FastStream execution was coupled to the legacy Client lifecycle. This change introduces an independent STOMP core and explicit facade adapters. Native FastStream runs the core directly and confirms broker receipts by default. An explicitly injected Client preserves that object's identity, overridden methods, lifecycle hooks, and historical defaults.

The core owns frames, validated immutable configuration, errors, TCP transport, and execution. It imports no legacy modules and can run under a different package name. Strict wire encoding and decoding share one codec module; the historical tolerant parser remains at the legacy facade boundary. Runtime handles facade availability; a running lifetime owns acquisition, workers, and ordered shutdown. Recovery owns generation changes, restoration, and its status projection. Commands own submission, receipt completion, and cancellation. Subscriptions own installation and admission, acknowledgements stay on their original session, and transactions own replay journals and ambiguous commit outcomes.

Validation separates header, command, and body rules. Connection-race cleanup owns cancellation and loser closure. Recovery stores one shutdown marker and at most one acquisition task, matching the generation lock's actual invariants, while the transport remains the sole owner of receive timing. Shared frame unions replace repeated ad hoc type combinations. Legacy connection and delivery fallbacks remain explicit adapter policies; multihost validation and diagnostic translation each separate parsing from result construction.

Shutdown closes admission for the whole running lifetime, drains existing handlers, unsubscribes, stops workers, and closes the connection. A handler can still publish or settle while draining; subscriptions created or restored during that drain cannot start new handlers. Cleanup operations own their tasks, current-session writes own both submission and completion, and one watchdog checks heartbeat and idle deadlines independently of heartbeat transmission.

Native connections implement STOMP 1.2 with strict incremental decoding, bounded incomplete input, required-header and command-direction checks, exact content lengths, valid escapes, and mandatory frame terminators. Limits default to 1,024 headers, 16 KiB per line, 64 KiB of headers, and 64 MiB per body. Extension headers and empty values remain valid. The first repeated header wins, and optional headers such as ERROR.message stay optional. Manually acknowledged messages must have an ACK identifier before admission.

ERROR is terminal for every session. Receipt handling atomically retires all correlations before notifying observers: an exact receipt ID rejects its matching operation; other pending operations report connection loss with an unknown outcome. Already confirmed results survive later errors, including errors that interrupt transport drain. A graceful DISCONNECT requests and waits for its receipt and is the last client frame, including heartbeats. Ordinary receipt confirmation is the library's default policy; STOMP makes those requests optional.

Compatibility adapters retain previous constructors, signatures, dataclass extension, mutable facade objects, callbacks, transaction decorators and replay lists, transport/lifespan hooks, parser and frame identities, and diagnostic payloads. Legacy handshake issue unions retain their original variants. Historical parsing, handshake tolerance, missing-ACK logging, unlimited admission, and write-only defaults are selected explicitly by the legacy adapter. The intentional behavior change is terminal ERROR handling: uncorrelated ERROR frames no longer incorrectly mark all pending operations as rejected. Artemis can omit the recommended receipt-id, which now produces an unknown connection-loss outcome.

The source reading order, ownership map, and migration notes include the native API and protocol rules. The FastStream adapter requires stompman >=3.16.0. The existing AnyIO <4.15 compatibility bound and websockets >=14 extra remain in place.

Validation at abaac31:

  • All 868 tests pass locally on Python 3.13 with both asyncio backends and ActiveMQ Artemis and Classic. Focused coverage for the strict codec and tolerant compatibility parser is 100%.
  • Regressions cover strict wire decoding, receipt ordering, blocked writes, cancellation, recovery during shutdown, settlement, transaction replay, and legacy public contracts. TCP peers verify terminal socket closure and no subsequent client bytes.
  • Strict mypy passes for 94 source files; Ruff, formatting, and diff checks pass. A 3,000-stream differential parser comparison matches the previous implementation, and independent review has no remaining material findings.
  • Wheels and sdists build. An isolated installation verifies package contents, injected Client behavior, TestStompBroker, confirmed native TCP publication, and a real WebSocket exchange using websockets 14.0.
  • All six CI jobs pass on this commit: lint, typing, and the full test suite on Python 3.11–3.14.

This remains a draft for review.

@vrslev vrslev changed the title Introduce independent STOMP runtime and facade adapters Build a self-contained STOMP core with explicit facade adapters Sep 7, 2026
@vrslev vrslev changed the title Build a self-contained STOMP core with explicit facade adapters Build an independent STOMP core with compatible facade adapters Sep 7, 2026
@vrslev vrslev changed the title Build an independent STOMP core with compatible facade adapters Build an independent STOMP 1.2 core with compatible facade adapters Sep 7, 2026
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