Skip to main content
EventLog is a persistent, replayable progress-event stream over ordered KV storage. emit(type, payload) assigns a strictly increasing seq and persists the row, so consumers can replay events in order after a restart, or resume from a cursor (read(afterSeq)). Retention is count-based: the log keeps at most retain rows (default 1000), and each emit past that bound prunes the oldest rows — the storage footprint stays bounded regardless of emit rate, and pruning never reuses a seq.

Obtaining an EventLog

An agent constructs its own log over the actor’s durable storage — typically once, as a field:
The first argument is the actor’s ctx.storage, so the log shares the actor’s durability and single-writer guarantees; retain bounds how many rows are kept (default 1000). One actor can hold several logs for unrelated streams — each EventLog keys its rows independently.

Worked example: streaming progress from a long-running task

The pattern has three parts: the task emits durable events, the socket server replays and pushes them, and the client subscribes from a cursor. 1. Emit from the task, push to live watchers. emit persists the row and returns its seq; reading strictly after seq - 1 yields the stored row to hand to AgentSocketServer’s broadcastEvent:
2. Subscribe on the client. AgentClient’s onEvents delivers each event in seq order; from replays missed events after a disconnect, so a page that reconnects mid-task picks up exactly where it left off:
Because the log is durable and seq never regresses, this survives agent restarts mid-task: the replay comes from storage, not from anything held in memory.

emit()

emit(type, payload): Promise<number>
Append one event; returns its assigned seq. Atomic (counter + row + pruning). If the log is at its retention bound, the oldest row(s) are pruned in the same transaction. Parameters Returns Promise<number>

read()

read(afterSeq?, limit?): Promise<StoredEvent[]>
Read retained events in seq order. afterSeq is an exclusive cursor: only events with seq > afterSeq are returned (default 0 = from the start). limit caps the number of rows; omitted = all retained rows (paginates internally past the per-list cap). Parameters Returns Promise<StoredEvent[]>

count()

count(): Promise<number>
Total events ever emitted (the current seq high-water mark). Returns Promise<number>

StoredEvent

A progress event as persisted: assigned a monotonic seq + wall-clock stamp. Properties at
at: Date
Wall-clock stamp at emit time; informational only (ordering is by seq).
payload
payload: unknown
Arbitrary payload. MUST be codec-safe (JSON-native + Date/Map/Set/ ArrayBuffer/TypedArray/Buffer/BigInt/RegExp) — it is stored via ctx.storage.put, which throws CodecError on functions, class instances, or circular refs.
seq
seq: number
Monotonic sequence number, assigned on emit — never reused, only moves forward.
type
type: string
Caller-chosen event kind (e.g. “progress”).

EventLogOptions

Options for the event log. Properties retain?
optional retain?: number
Maximum number of event rows kept (count-based retention). Once the log holds this many rows, each new emit prunes the oldest. Default 1000.