Skip to content

Watching a run

A run reports what it is doing as a sequence of events. Each one carries a number, and that number is where you resume from. It is a counter, not a clock: two changes in the same millisecond are two events, and nothing you read depends on our clock agreeing with yours.

GET /katara/v1/orgs/{org_id}/environments/{environment_id}/runs/{id}/events

Send Accept: text/event-stream and you get server-sent events whose id is the sequence. A browser EventSource sends Last-Event-ID when it reconnects, so resumption costs you nothing to write. EventSource cannot send an Authorization header, so it works only from a page on Katara’s own origin with your sign-in; from anywhere else, read the stream with fetch and a bearer key. A stream lasts at most ten minutes, with a keep-alive every 20 seconds; reconnect from the last id after that. Without that header the same events come back as one page of JSON, which is what a script wants.

const events = new EventSource(url, { withCredentials: true });
events.addEventListener("run.completed", event => {
const { sequence, snapshot } = JSON.parse(event.data);
console.log(sequence, snapshot?.steps);
});

For a client that keeps its own position, from is the same resumption point:

const page = await client.runEvents(scope, runId, lastSequence);
for (const event of page.data) apply(event);

next_sequence is the number to resume from next time. Passing zero, or leaving from out, says you hold nothing yet; you are given what is still kept rather than being told anything is missing.

A finished run ends the stream instead of holding the connection open. A stream that has been open a long time also ends on its own; reconnect with the last id you saw and you lose nothing.

Once a run has finished, the steps along the way are eventually dropped. What happened to the run is kept. retained_from is the earliest sequence still held, and resuming from a point that would skip held-back events (from + 1 below retained_from) answers 410 with stream_gone rather than handing you the next thing that still exists, because a gap you could not see is worse than an error you can.

On a 410, read the run itself to see where it got to and carry on from there.

Reading events needs the same permission as reading the run. That permission is rechecked on every page, so access removed while a stream is open ends it.