You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(execution): stop run-buffer failures from stranding resumed executions (#6187)
* fix(resume): stop a failed run-buffer publish from stranding a resumed execution
The run buffer is a replay convenience for stream readers; the durable
execution record is authoritative. A failed terminal event publish was
deciding the outcome of work that had already run: it threw, the resume
was marked failed, and the paused execution was left paused forever.
That path is also not retryable — the workflow had already executed — so
the next resume attempt re-ran its side effects.
Degrade instead. Record the terminal status on the stream meta so readers
are not left polling an 'active' stream, log the failure, and let the
resume settle on its real result. The same treatment applies when the
terminal event is never published at all, which previously synthesized an
error for the same stranding effect.
Removes the now-unreachable TERMINAL_PUBLISH_ERROR constant and its
branch. Pre-execution buffer failures stay fatal and retryable, since no
work has happened yet.
* fix(execution): give per-user Redis budget keys a fixed window
The per-user byte budget refreshed its TTL on every accepted write, so for
any user who never went a full TTL without writing, the key never expired.
The per-execution data it accounted for kept expiring underneath it, so the
counter accrued bytes Redis had already dropped and drifted toward the
ceiling. On reaching it, every subsequent write for that user was rejected
until they stopped writing for a full TTL — and since a rejected write does
not refresh the TTL, it recovered on its own and then refilled.
User keys now get a fixed window: the TTL is set when the key is created and
never extended. Applied to all five Lua scripts that touch the key so the
writers cannot drift apart. Execution-scoped keys keep sliding — they are
refreshed on the same schedule as the data they account for, so their
counter and bytes stay in step.
* fix(execution): heal a user budget key that somehow has no expiry
The no-op branch of the flush script dropped the user-key EXPIRE outright
rather than guarding it like every other site. No current path can create
the key without an expiry, but if one ever did, that branch was the one
place that would never give it one — and a user counter with no expiry is
the unbounded version of the bug this series fixes.
Guard it instead, so the branch heals such a key rather than skipping it,
and so all five scripts read the same way.
* fix(stream): end a replay cleanly when terminal metadata has no terminal event
Terminal metadata is the authoritative end-of-run signal — the happy path
writes it atomically with the terminal event, and a run whose terminal
event could not be buffered records the status on its own. The reader
required both, so the degraded case threw and turned a replay that was
merely incomplete into a broken one.
Metadata without a matching event means the buffer degraded, not that the
run is still going. Log it and close the stream: the reader has already
received every event that was buffered, and the durable record is
unaffected either way.
0 commit comments