angzarr_client.destinations¶
Destinations context for sagas and process managers.
Provides type-safe access to destination sequences for command stamping. Sagas and PMs receive destination_sequences from the framework and use this class to stamp commands with the correct sequence numbers.
- Design Philosophy:
Sagas and PMs should NOT rebuild destination state to make decisions. They receive only sequences for command stamping. Business logic belongs in aggregates - sagas/PMs just translate and coordinate.
- Example usage:
@handles(OrderCreated) def handle_order(self, event: OrderCreated, destinations: Destinations):
cmd = ReserveInventory(order_id=event.order_id, quantity=event.quantity) destinations.stamp_command(cmd, “inventory”) return cmd
Classes¶
Context for saga/PM handlers providing access to destination sequences. |
Module Contents¶
- class angzarr_client.destinations.Destinations(sequences: dict[str, int])¶
Context for saga/PM handlers providing access to destination sequences.
Sagas and PMs receive destination sequences (not full EventBooks) from the framework. This class provides a stamp_command() helper to set the correct sequence number on commands before they’re sent.
Why sequences only?¶
Sagas and PMs are translators/coordinators - they should NOT make business decisions based on destination state. If you need external information: 1. Inject it as a fact 2. Let aggregates decide (they validate commands) 3. Use sync mode for immediate feedback on command results
- sequences¶
Map from domain name to next sequence number.
Create a Destinations context from a sequence map.
- param sequences:
Dict mapping domain name to next sequence number. Typically from proto’s destination_sequences field.
- classmethod from_proto(destination_sequences: dict[str, int]) Destinations¶
Create from proto’s destination_sequences map.
- Parameters:
destination_sequences – Map from ProcessManagerHandleRequest or SagaHandleRequest proto.
- Returns:
Destinations instance with the sequences.
- sequence_for(domain: str) int | None¶
Get the next sequence number for a destination domain.
- Parameters:
domain – The target domain name.
- Returns:
The next sequence number, or None if domain not found.
- stamp_command(cmd: angzarr_client.proto.angzarr.types_pb2.CommandBook, domain: str) angzarr_client.proto.angzarr.types_pb2.CommandBook¶
Stamp a command with the correct sequence for its destination domain.
Modifies the command’s page headers in-place with the sequence number.
- Parameters:
cmd – The CommandBook to stamp.
domain – The target domain (must be in destination_sequences).
- Returns:
The same CommandBook (for chaining).
- Raises:
InvalidArgumentError – If domain is not in destination_sequences. Carries
code=MISSING_DESTINATION_SEQUENCEanddetails["domain"]=<domain>for cucumber assertions. Check youroutput_domainsconfig when you see this. Audit #64.
- static deferred_header(source_cover, source_seq: int) angzarr_client.proto.angzarr.types_pb2.PageHeader¶
Build a PageHeader carrying an
AngzarrDeferredSequence.Accepts either a
Coverwrapper (the canonical post-B2 form passed to handlers by the framework) or a rawCoverproto. Internally the proto is what gets copied into theAngzarrDeferredSequencepayload.Use this on saga-produced commands so the framework can dedupe on
(source.root, source_seq, target.root). AMQP at-least-once redelivery of the trigger event then becomes a no-op at the destination aggregate’s pipeline (cached events returned without re-invoking business logic), instead of relying on a business guard that surfaces as an idempotent-failure-shaped retry storm.