Events
Every unit transition and every scaling change is written to an append-only log, in the same database transaction as the change. Read it with a cursor.
curl
Code
TypeScript
Code
Python
Code
The envelope (contract v1)
Code
seq is gapless and strictly increasing per Workload, so a cursor never skips an event that commits late. Consumers must ignore unknown fields and unknown event types: additions are never a new version.
| Type | data |
|---|---|
unit.created, unit.starting, unit.ready, unit.stopped, unit.idle, unit.busy, unit.draining | |
unit.accepting, unit.not_accepting | |
unit.allocated, unit.allocation_delivered, unit.allocation_undelivered | |
unit.exited | {code, restarted} |
unit.failed | {reason} |
unit.destroyed | {reason} (expired when destroyed after being stopped too long) |
units.scaled | {from, to, reason}; unit is null |
rollout.started, rollout.completed, rollout.paused | unit is null |
webhook.ping (webhook deliveries only) | |
events.gap (webhook deliveries only) | {from_seq, to_seq}: events a re-enabled webhook missed because they were no longer kept |
unit.ready and unit.allocated carry the unit's private name and public address, so a matchmaker needs no second read. idle and busy are emitted on transitions only.
Parameters
| Parameter | Meaning |
|---|---|
after | the last seq you saw; 0 starts at the oldest kept event |
types | comma-separated list to keep |
limit | up to 500 |
wait | 0 to 30 seconds: with nothing new, hold the request and return the moment an event arrives |
The response is {events, next_after, oldest_retained_seq}. Send next_after as the next after. Events are kept 30 days. A cursor older than that answers 410 cursor_expired with resume_after.
Delivery is at-least-once
Persist the last seq you processed in the same transaction as your own effect, and treat a repeated seq as already done. This is the same rule that makes webhooks safe.
