Genace

SSE reconnect without event IDs: recover the latest generation snapshot

A reconnecting observer needs to recover the resource state, not recreate a connection’s history. Genace’s current SSE formatter emits event and data fields without event IDs. Sending Last-Event-ID therefore does not provide a supported replay contract. Keep a durable job identifier and use a fresh status snapshot to decide what should happen next.

Persist identity before opening the stream

Save the accepted job_id in your application operation record. The stream is then an optional view of a known job. A browser refresh, sleep event, or proxy timeout can destroy the connection while the generation continues. If the only copy of the identifier lives inside that connection handler, recovery becomes needlessly fragile.

The public stream starts with a progress record describing current state and later emits updates and a terminal event. It can close because of the route’s declared sixty second maximum duration or another component’s limit. A close without a terminal record does not establish a failed generation.

Reconcile before reconnecting

Use an application state transition like the following. This is a local observer design, not a new Genace endpoint or state enum.

stream disconnected
  -> mark observer disconnected, preserve saved job ID
  -> GET /api/v1/jobs/{id}?wait=0
      -> succeeded: validate outputs and finalize locally
      -> failed/canceled: preserve terminal error and accounting
      -> queued/running: reconnect with bounded backoff or poll
      -> HTTP failure: retain last snapshot and retry the read policy

Use one recovery owner per local operation. If a UI effect, a backend collector, and a reconnect timer all open their own streams, your request count can multiply while the interface still shows only one job. Assign each component a responsibility and stop stale observers.

Make repeated terminal information harmless

A reconnect can return a terminal progress snapshot immediately before done or error. Your local finalization path should update the same operation record conditionally and schedule delivery once. This is application deduplication of result handling, not remote creation idempotency.

Do not expect to recover every intermediate percentage. Progress is nullable and the stream has no sequence number. If your product requires an audit history, record observations in your own storage with local timestamps and explicitly label them as samples. Do not describe those samples as a complete upstream event log.

Keep authentication on the correct side

The upstream stream requires a bearer key. Browser-native EventSource does not offer a general custom Authorization-header option. Use an authorized backend relay or a trusted fetch-based client, and keep the key out of URL parameters. A replay header cannot solve credential routing or local tenant authorization.

Recovery tests

Disconnect after initial progress, after a terminal progress record, and immediately before a terminal event. In each case, verify one GET against the original job settles the local decision. Test failed reads without erasing the last known state and verify backoff stops at an application deadline.

Confirm reconnecting never calls the generation POST. Test repeated success information against your publication path to prove only one local delivery operation is created. Finally, inspect telemetry to ensure connection counts are not mistaken for new render counts.

See SSE delivery, durable job recovery, and chunk parsing.

Continue with code and integration

Where these facts come from