Skip to content

fix(core): use effective step timeout for stalled tasks - #664

Merged
jumski merged 1 commit into
mainfrom
09-02-issue_621_effective_step_timeout
Sep 2, 2026
Merged

fix(core): use effective step timeout for stalled tasks#664
jumski merged 1 commit into
mainfrom
09-02-issue_621_effective_step_timeout

Conversation

@jumski

@jumski jumski commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix stalled-task recovery to use the effective step timeout instead of always using the flow timeout.

This PR stacks directly on #663 (09-01-issue_645_failed_run_terminalization) and preserves its run, step-state, and task eligibility guards.

Root cause

start_tasks() sets PGMQ visibility from the effective timeout:

coalesce(step.opt_timeout, flow.opt_timeout) + 2

requeue_stalled_tasks() used only flows.opt_timeout. A short step timeout could therefore make the PGMQ message visible while its task row remained started until the longer flow timeout and recovery buffer expired.

Behavior

Recovery now requires:

started_at < now()
  - (coalesce(step.opt_timeout, flow.opt_timeout) * interval '1 second')
  - interval '30 seconds'

The comparison stays strict. A null step timeout inherits the non-null flow timeout.

The PGMQ-only two-second margin is not added to recovery. Adding it again would change the existing 30-second recovery grace to 32 seconds. The 15-second cron cadence can add up to roughly 15 seconds after eligibility.

The change preserves:

  • run.status = 'started', step_state.status = 'started', and task.status = 'started';
  • permanently_stalled_at is null and FOR UPDATE OF task SKIP LOCKED behavior;
  • attempts and requeue counters;
  • three successful requeues before permanent stall;
  • immediate visibility through set_vt_batch(..., 0);
  • archive and permanent-stall behavior.

Tests

Added effective_step_timeout.test.sql with deterministic timestamps inside one transaction:

  • flow 60 / step 5: exactly 35 seconds stays started; 36 seconds requeues;
  • flow 5 / step 60: 36 seconds stays started; 91 seconds requeues;
  • flow 5 / null step timeout: 36 seconds requeues through flow fallback.

Before the source fix, the focused test failed 5 of 10 assertions for the expected reason. The short step override returned 0 and stayed started at 36 seconds. The long step override requeued at 36 seconds, so its later 91-second call returned 0.

After the source fix:

  • focused test: 1 file, 10 tests, pass;
  • all stalled-recovery tests: 6 files, 54 tests, pass;
  • full pgTAP: 285 files, 1326 tests, pass.

Migration and release note

Atlas generated 20260901203454_pgflow_temp_effective_step_timeout.sql. It replaces pgflow.requeue_stalled_tasks(), includes the cumulative #645 guards, and performs no backfill.

Added a separate patch changeset for @pgflow/core. The fixed release group expands the patch at release time.

Checks

  • pnpm nx verify-migrations core --skip-nx-cache — pass
  • pnpm nx gen-types core --skip-nx-cache — pass; no generated type diff
  • pnpm nx verify-gen-types core --skip-nx-cache — pass
  • pnpm nx test:pgtap core --skip-nx-cache — pass; 285 files, 1326 tests
  • pnpm nx test core --skip-nx-cache — pass
  • pnpm nx lint core --skip-nx-cache — pass; 0 errors and 2 existing type-test warnings
  • pnpm nx build core --skip-nx-cache — pass
  • pnpm changeset status — pass; patch fixed group detected
  • git diff --check — pass

pnpm nx fix-sql core hit the known Sqruff CLI mismatch: error: unexpected argument '--force' found. The direct repository fallback, sqruff --config=.sqruff fix --parsing-errors pkgs/core/schemas/, processed 37 files and found nothing to fix. Direct Sqruff lint also passed.

Two fresh independent Sol xhigh review rounds returned APPROVED with no required findings.

Out of scope

The stack still contains temporary migrations, so the main-targeted temporary-migration check can fail until the settled release sequence consolidates them. This PR does not consolidate the parent migration.

Fixes #621

@changeset-bot

changeset-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cb52bb5

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 Patch
pgflow Patch
@pgflow/client Patch
@pgflow/edge-worker Patch
@pgflow/dsl Patch

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 Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

@nx-cloud

nx-cloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit cb52bb5

Command Status Duration Result
nx run edge-worker:test:integration ✅ Succeeded 5m 49s View ↗

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


☁️ Nx Cloud last updated this comment at 2026-09-02 02:09:49 UTC

@jumski
jumski force-pushed the 09-02-issue_621_effective_step_timeout branch from bb4ae5b to 2131023 Compare September 2, 2026 00:40
@jumski
jumski force-pushed the 09-02-issue_621_effective_step_timeout branch 2 times, most recently from 7a9e910 to 256879e Compare September 2, 2026 00:58
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🔍 Preview Deployment: Website

Deployment successful!

🔗 Preview URL: https://pr-664.pgflow.pages.dev

📝 Details:

  • Branch: 09-02-issue_621_effective_step_timeout
  • Commit: 2cfe6eb34c86575bf18e74a06ff4aa7fbe3dd9e8
  • View Logs

_Last updated: _

@jumski
jumski changed the base branch from 09-01-issue_645_failed_run_terminalization to graphite-base/664 September 2, 2026 01:11
@jumski
jumski force-pushed the 09-02-issue_621_effective_step_timeout branch from 256879e to ec55330 Compare September 2, 2026 01:11
@graphite-app
graphite-app Bot changed the base branch from graphite-base/664 to main September 2, 2026 01:11
@jumski
jumski force-pushed the 09-02-issue_621_effective_step_timeout branch from ec55330 to db903fb Compare September 2, 2026 01:11
Stalled recovery used only the flow timeout, so step overrides could leave tasks started long after their PGMQ messages became visible.

Use the same step-over-flow timeout selection as start_tasks while preserving the 30-second recovery buffer, requeue limits, permanent-stall behavior, and the #645 parent-state guards. The PGMQ-only two-second visibility margin remains unchanged.
@jumski
jumski force-pushed the 09-02-issue_621_effective_step_timeout branch from db903fb to cb52bb5 Compare September 2, 2026 01:32

jumski commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Sep 2, 5:21 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Sep 2, 5:22 AM UTC: @jumski merged this pull request with Graphite.

@jumski
jumski merged commit 35d261b into main Sep 2, 2026
38 of 40 checks passed
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🚀 Production Deployment: Website

Successfully deployed to production!

🔗 Production URL: https://pgflow.dev

📝 Details:

  • Commit: 35d261b95b12b1b47aca4b5103f9e4302be4a747
  • View Logs

Deployed at: 2026-09-02T07:22:06+02:00

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.

requeue_stalled_tasks() uses flow timeout instead of effective step timeout

1 participant