Skip to main content

Resumable SSE + Graceful Drain

The problem

Two related production scenarios:
  1. Flaky network. A mobile client streaming an agent response loses signal mid-stream. When it reconnects, you want to resume from where it dropped, not restart from scratch.
  2. Graceful K8s rollout. A pod receives SIGTERM. You don’t want to drop in-flight agent runs on the floor; you want each one to finish its current step, persist a checkpoint, and exit cleanly so the next pod can pick up.
Agentium ships small primitives for both.

Resumable SSE

Concept

Every event emitted during an agent run is recorded in an in-memory ring buffer keyed by runId. Each event gets a monotonically increasing numeric id. When a client reconnects with the standard Last-Event-ID HTTP header, the server replays any events the client missed before resuming.

InMemoryEventLog

API

Default singleton

defaultEventLog is exported as a process-wide shared instance so multiple endpoints can record / replay against the same buffer without coordinating:

formatSSEEvent(ev)

Renders an SSEEvent for the wire:
(Trailing blank line per SSE spec.) If ev.event is set, an event: <name> line is also emitted.

Full reference handler

Storage requirements

InMemoryEventLog is in-process only. If you have multiple instances behind a load balancer, the client needs to reconnect to the same instance OR you need a shared backend. Implementing a Redis-backed SSEEventLog is straightforward — just match the interface (record, since, all, finalize, drop). On the roadmap as RedisEventLog.

Graceful Drain

Concept

When SIGTERM hits, you want to:
  1. Stop accepting new requests.
  2. Let in-flight requests finish their current LLM call / tool roundtrip.
  3. Persist a resumable checkpoint.
  4. Exit.
DrainController is a small primitive for cooperative shutdown.

DrainController

API

The controller is intentionally low-level. Higher-level integration (e.g. Agent.requestDrain() that automatically saves a checkpoint) is on the roadmap. For now, wire it yourself.

Full drain flow

When the workflow resumes on the next pod, it picks up from the last saved checkpoint via Workflow.replay(checkpointId).

See also