Skip to content

fix(core): terminalize permanently stalled tasks through whenExhausted - #713

Open
jumski wants to merge 1 commit into
mainfrom
689-terminalize-stalled
Open

jumski wants to merge 1 commit into
mainfrom
689-terminalize-stalled

Conversation

@jumski

@jumski jumski commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #689. Independent of the worker startup handshake in #711.

recovery transaction
  retry budget exhausted → mark permanently stalled + archive message
  COMMIT

separate escalation cron transaction
  lock and recheck run → step → task
  marked started/queued task → fail_task()
    apply whenExhausted: fail | skip | skip-cascade
    preserve attempts_count as committed claims

The existing recovery setup configures both cron jobs with one interval. Upgrade wiring preserves installed schedules and inactive/absent recovery choices. Historical marked queued leftovers are included; unmarked queued and terminal tasks stay unchanged.

Upgrade and deployment guidance restores recorded activation values instead of enabling everything. Saved cron values must be JSON booleans; unknown or malformed state never enables a job. Includes a core changeset, generated migration/types, pgTAP coverage, and upgrade fixtures.

Evidence

  • Before: recovery stamped and archived tasks after its requeue limit but left them active. Late failure callbacks could retry an archived task below max_attempts.
  • After: marker-aware exhaustion reuses the existing policy transitions, while the separate sweep repairs historical started/queued rows without synthetic claims. Regression coverage includes policies, callback races, map/private queues, and cron state preservation.
  • Prior recorded checks: the source implementation commit reports 323 pgTAP files / 1,741 assertions; 279 worker unit tests; 13 Edge Function E2E tests; 14 portable-runtime E2E tests; migration/type checks; website build. The docs correction reports restoration checks for nine absent/false/true state combinations and malformed-state rejection. These are prior results, not new-base runtime revalidation.
  • Relocation: combine the two local commits into one commit on 689-terminalize-stalled, based on main; recalculate Atlas checksums without fix(worker): coordinate pending starts with invocation handshakes #711’s migration. Runtime suites were not rerun for this transfer. Normal commit and pre-push hooks remain enabled.

Merge Danger

Door: one-way for data effects after escalation runs. Code can be reverted; completed transitions and downstream side effects cannot be undone automatically.

Blast Radius: recovery

Historical marked tasks follow the existing exhaustion policy after upgrade. In particular, skip can enqueue dependent business work. Inspect the documented backlog before upgrade. Pause both cron jobs and the relevant workers/callbacks when downstream execution must stop, then restore each recorded state exactly. Inactive cron jobs alone do not prevent marker-aware failure callbacks. No production migration or deployment is part of this PR submission.

Recovery archived permanently stalled task messages but left their tasks and runs active. Treat the permanent-stall marker as exhaustion in fail_task() without inflating attempts_count, and use a separate escalation cron transaction to apply the existing fail, skip, or skip-cascade policy to marked started and queued tasks. Preserve terminal-state guards, diagnostic markers, stored queue routing, and installed recovery schedules and activation choices.

Restore saved cron booleans exactly in the upgrade guidance rather than enabling every paused job; reject malformed saved state and require the snapshot to survive the SQL session. Preserve recorded enabled values in the deployment guide too.

Combine the changes from dd41e5dfe and d4831bd79 onto the independent 689-terminalize-stalled branch based on main. Recalculate atlas.sum for this branch without the unrelated worker-startup migration from #696. The original commits remain recoverable at backup/689-misplaced-d4831bd79.

The original implementation commit records pgTAP, worker, E2E, migration/type, and website checks; the documentation correction records rolled-back restoration checks and website lint/build. This relocation preserves their code changes but does not treat those earlier results as fresh runtime validation on the new base. Repository hooks run normally for this commit and submission.

Fixes #689
@changeset-bot

changeset-bot Bot commented Nov 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: daa1753

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@pgflow/core Minor
pgflow Minor
@pgflow/client Minor
@pgflow/edge-worker Minor
@pgflow/dsl Minor

Not sure what this means? Click here to learn what changesets are.

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

jumski commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@nx-cloud

nx-cloud Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit daa1753

Command Status Duration Result
nx run-many -t build --projects=dsl,core,cli ✅ Succeeded 5s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-11-02 20:26:10 UTC

This branch has not been deployed

No deployments
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.

Terminalize tasks after the stalled-task requeue limit

1 participant