Skip to content

fix(run-engine): correct park deadline and snapshot state for debounced parked runs - #4708

Merged
0ski merged 1 commit into
oskar/feat-external-id-dashboardfrom
oskar/fix-park-deadline-rearm
Aug 19, 2026
Merged

fix(run-engine): correct park deadline and snapshot state for debounced parked runs#4708
0ski merged 1 commit into
oskar/feat-external-id-dashboardfrom
oskar/fix-park-deadline-rearm

Conversation

@0ski

@0ski 0ski commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Two defects that surface when a run parked on an external deployment id gets pushed by a debounce key. Both were reproduced against a local instance before being fixed.

1. The run is expired before it is due

now      | status  | statusReason                  | delayUntil | expiredAt
13:57:06 | EXPIRED | EXTERNAL_DEPLOYMENT_NOT_FOUND | 14:01:37   | 13:57:02

Killed 4m35s before its own scheduled start, blaming a missing deployment.

Why. The park deadline is armed once, when the run is first parked, from max(now, delayUntil) + deadline. Debounce pushes delayUntil out afterwards and nothing re-arms it:

  • rescheduleDelayedRun reschedules enqueueDelayedRun:<id>, not expireParkedExternalDeploymentRun:<id>
  • the redis-worker reschedule is an update-only ZADD … XX, and a parked run has no enqueueDelayedRun job, so that call is a silent no-op

Repeat triggers on one key walk delayUntil away from a deadline that no longer moves. Once it crosses, the run dies while parked and not yet due.

Fix. The expiry job already loads delayUntil, so it re-arms from the current value and returns instead of expiring a run that is not due.

The guard lives in the expiry job rather than the debounce path deliberately: it covers every caller that moves delayUntil, so a future call site can't reintroduce this by forgetting to re-arm. It stays bounded by the debounce max-duration contract, so a hot key can't postpone expiry indefinitely.

2. The run reports itself as delayed while it is parked

RUN_CREATED | PENDING_VERSION | Run is waiting for a deployment of 'debounce-test-2'
DELAYED     | DELAYED         | Delayed run was rescheduled to a future date   ← after one debounce push

The row stays PENDING_VERSION; the latest snapshot claims DELAYED, so the run page describes a parked run as delayed. Happens on the first push.

Fix. rescheduleRun hardcoded DELAYED/DELAYED. The snapshot statuses are now supplied by the caller and default to DELAYED, so the ordinary delayed path is byte-identical, and rescheduleDelayedRun passes the parked statuses through when the run is parked.

Reproducing

Repeated triggers on one debounce key against an id that hasn't landed:

curl … -d '{"options":{"externalDeploymentId":"x","debounce":{"key":"k","delay":"5m"}}}'

Three triggers correctly fold into one parked run; the defects show up on the pushes.

Testing

Two tests, each verified red before green and failing alone:

  • a run whose delay was pushed past the deadline stays PENDING_VERSION instead of expiring
  • a debounce push on a parked run leaves a RUN_CREATED/PENDING_VERSION snapshot, not DELAYED

56 passed across parking, pendingVersion, delayedRunSystem and debounce; 43 passed in PostgresRunStore. Typecheck, lint, format clean.

Notes

@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: f62294a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a9360ac4-8cd9-412c-918a-df5bade6c2e7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@0ski 0ski changed the title fix(run-engine): re-arm the park deadline when a parked run is not due yet fix(run-engine): correct park deadline and snapshot state for debounced parked runs Aug 19, 2026
@0ski
0ski force-pushed the oskar/fix-park-deadline-rearm branch from 7aab9b9 to b40b22a Compare August 19, 2026 14:51
@0ski
0ski marked this pull request as ready for review August 19, 2026 14:54

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

Open in Devin Review

Comment thread internal-packages/run-engine/src/engine/systems/delayedRunSystem.ts
Comment thread internal-packages/run-engine/src/engine/systems/delayedRunSystem.ts
Comment thread internal-packages/run-engine/src/engine/systems/delayedRunSystem.ts
…ed parked runs

Two defects surface when a run parked on an external deployment id is pushed by
a debounce key. Both were reproduced against a local instance before fixing.

1. The run is expired before it is due.

The park deadline is armed once, when the run is first parked, from
max(now, delayUntil) + deadline. Debounce pushes delayUntil out afterwards:
rescheduleDelayedRun reschedules enqueueDelayedRun:<id>, and the redis-worker
reschedule is an update-only ZADD, so expireParkedExternalDeploymentRun:<id> is
never re-armed. Repeat triggers on one key walk delayUntil past a deadline that
no longer moves, and the run is expired with EXTERNAL_DEPLOYMENT_NOT_FOUND
before it was ever due to start. Observed: a run due at 14:01:37 expired at
13:57:02.

The expiry job already loads delayUntil, so it now re-arms from the current
value and returns instead of expiring a run that is not due. Putting the guard
there rather than in the debounce path covers every caller that moves
delayUntil, and it stays bounded by the debounce max-duration contract.

2. The run reports itself as delayed while it is parked.

rescheduleRun hardcoded a DELAYED/DELAYED execution snapshot, so a debounce push
left the run row on PENDING_VERSION while its latest snapshot claimed DELAYED,
and the run page described a parked run as delayed. The snapshot statuses are
now supplied by the caller and default to DELAYED, so the ordinary delayed path
is unchanged, and rescheduleDelayedRun passes the parked statuses through when
the run is parked.
@0ski
0ski force-pushed the oskar/fix-park-deadline-rearm branch from b40b22a to f62294a Compare August 19, 2026 15:20

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

@0ski
0ski merged commit 967dedc into main Aug 19, 2026
41 checks passed
@0ski
0ski deleted the oskar/fix-park-deadline-rearm branch August 19, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants