Architecture¶
a2akit is built around pluggable components that you can swap independently. Every component implements an ABC, and in-memory defaults are provided for local development.
Component Diagram¶
graph TD
HTTP["HTTP Server\n(FastAPI + SSE)"]
MW["Middleware\n(before / after dispatch)"]
ENV["RequestEnvelope\n(params + context)"]
TM["TaskManager\n(coordinates)"]
WA["WorkerAdapter\n(lifecycle)"]
EE["EventEmitter\n(facade)"]
HE["HookableEmitter\n(lifecycle hooks)"]
B["Broker\n(queues & schedules)"]
S["Storage\n(persistence)"]
EB["EventBus\n(event fan-out)"]
CR["CancelRegistry\n(cancel signals)"]
W["Worker\n(your code)"]
TC["TaskContext\n(execution API)"]
HTTP -->|raw request| MW
MW -->|"mutate envelope\n(extract secrets, headers)"| ENV
ENV -->|"params (persisted)"| TM
ENV -.->|"context (transient)"| B
TM -->|schedules tasks| B
TM -.->|reads / writes| S
TM -.->|subscribes| EB
TM -.->|cancel signals| CR
B -->|delegates execution| WA
WA -->|"handle(ctx)"| W
W -.->|uses API| TC
TC -->|emits via| HE
HE -->|decorates| EE
EE -->|writes| S
EE -->|publishes| EB
WA -.->|checks / cleanup| CR
Data Flow¶
A request flows through the system in this order:
- HTTP Request arrives at a FastAPI endpoint (
/v1/message:sendor/v1/message:stream). - Middleware pipeline runs
before_dispatchon aRequestEnvelope, extracting secrets and enriching transient context. - TaskManager receives the protocol params, creates or updates the task in Storage, and enqueues a run operation on the Broker.
- Broker delivers the operation to the WorkerAdapter.
- WorkerAdapter builds a
TaskContext, transitions the task toworking, and calls your Worker'shandle(ctx)method. - Worker uses
TaskContextmethods to emit artifacts, status updates, and lifecycle transitions. These flow through the EventEmitter to Storage (authoritative write) and EventBus (best-effort broadcast).
Components¶
TaskManager¶
Handles submission, validation, streaming, and cancellation. Coordinates between Broker, Storage, EventBus, and CancelRegistry — but never touches the Worker directly.
WorkerAdapter¶
Bridges the Broker queue to your Worker. Manages the lifecycle: dequeue, check cancel, build context, transition to working, call handle(ctx), cleanup.
EventEmitter¶
Facade that TaskContext uses to persist state (Storage) and broadcast events (EventBus) without knowing about either directly.
HookableEmitter¶
Decorator around EventEmitter that fires lifecycle hooks after successful state transitions. See Lifecycle Hooks.
Storage¶
Authoritative persistence layer for tasks, artifacts, and messages. Handles CRUD and data-integrity constraints (terminal-state guard, optimistic concurrency). See Storage Reference.
Broker¶
Task queue that schedules and delivers run operations to WorkerAdapter. Handles retry logic with ack/nack semantics. See Broker Reference.
EventBus¶
1:N event fan-out for SSE streaming. Publishes task status updates and artifact events to all subscribers. Best-effort delivery — if a publish fails, the state is still correct in Storage. See EventBus Reference.
CancelRegistry¶
Tracks cancellation signals per task. The worker checks ctx.is_cancelled cooperatively, and TaskManager has a force-cancel timeout fallback. See Cancellation Guide.
Middleware¶
Intercepts requests at the HTTP boundary. before_dispatch runs before TaskManager sees the request; after_dispatch runs after. See Middleware Guide.
Design Principles¶
Storage is authoritative; EventBus is best-effort. If an EventBus publish fails, the task state is still correct in Storage. Clients polling via GET will always see the right state. SSE subscribers may miss intermediate events but will always see the final status.
Pluggable backends. Swap Storage, Broker, EventBus, and CancelRegistry independently — e.g. PostgreSQL storage + Redis broker + Redis event bus. All backends implement their respective ABC.
Worker isolation. Your Worker only sees TaskContext. It doesn't know about Storage, Broker, or EventBus. This makes workers easy to test and portable across backend configurations.