Skip to content

Prevent deferred worker items from starving ready work - #51

Open
Thom Chiovoloni (thomcc-work) wants to merge 2 commits into
mainfrom
activity-admission-progress
Open

Thom Chiovoloni (thomcc-work) wants to merge 2 commits into
mainfrom
activity-admission-progress

Conversation

@thomcc-work

@thomcc-work Thom Chiovoloni (thomcc-work) commented Oct 30, 2026 •

Copy link
Copy Markdown

Summary

Prevent a backlog of deferred activities from starving unrelated ready work.

Previously, worker fetches selected eligible rows by queue ID alone. Deferred
items retained their original IDs, so if their retry delays expired before the
backlog drained, they could repeatedly be selected ahead of newer ready work.

Migration 0029 changes both session-aware and non-session fetches to order
eligible rows by visible_at, id. A deferred item therefore goes behind work
that was already ready, even after its delay expires.

  • Add idx_worker_ready_order on worker_queue(visible_at, id).
  • Preserve session ownership, tag filtering, lock handling, and attempt accounting.
  • Include a companion migration diff
    showing the function changes against baseline 0016 and the new index.
  • Update the changelog and migration guidance.

This is the PostgreSQL-provider companion to microsoft/duroxide#74. It does
not change activity admission APIs or introduce a Duroxide dependency bump.

Migration and compatibility

The migration replaces fetch_work_item without changing its signature or
return shape.

By default, the index is built non-concurrently inside the migration
transaction. For busy or large queues, pre-build the matching index with
CREATE INDEX CONCURRENTLY, outside a transaction, in each target schema
before applying the migration. The migration will then skip the expensive
index build.

Even when reusing a prebuilt index, the migration takes a SHARE lock on
worker_queue and holds it until transaction commit.
This blocks worker
fetch, acknowledge, abandon, and lock renewal, as well as orchestration
acknowledgements that write worker rows. The migration sets no lock_timeout,
so lock acquisition can wait indefinitely unless a deployment-session
lock_timeout is configured. Prebuilding reduces the work performed while
holding the lock; it does not make the migration lock-free.

Invalid prebuilt indexes, including those left by failed or cancelled
concurrent builds, are rejected without changing the migration ledger,
fetch function, or queued work.

See the rollout notes
for prebuild, verification, and repair instructions.

Already-running older providers can use the updated function. Older binaries
reject the new migration version on startup, so coordinate migration and
worker rollout.

Validation

Local validation at 9ae067b: 301 related unit, provider-validation, and
migration tests passed; one skipped.

Regression coverage includes:

  • Expired deferrals yielding to already-ready work across session/non-session
    and tagged/untagged combinations.
  • Rejection of an invalid index left by a failed concurrent build, with
    before/after snapshots proving the migration ledger, fetch function,
    queued work, and index state remain unchanged.
  • Successful migration with a valid concurrently prebuilt index, verifying
    that the existing index is reused.
  • A unit test requiring embedded migration versions to be unique and
    strictly increasing.

The worker progress tests now reuse panic-safe schema cleanup.

Order eligible worker items by visibility time, then queue ID, so expired
deferrals cannot repeatedly overtake work that was already ready.

Add migration 0027 and a matching index, preserving session ownership,
tag filtering, locking, and attempt accounting. Add regression tests for
session/non-session and tagged/untagged work, and document rollout impact.
Renumber the migration to 0029 and add its baseline-0016 diff. Centralize rollout guidance, including concurrent index preparation and the SHARE lock retained even when the build is skipped.

Reject invalid prebuilt indexes without changing the migration ledger, fetch function, or queued work. Add red/green regression coverage, enforce unique increasing embedded versions in a unit test, refresh the embed marker, and reuse panic-safe test schema cleanup.

Validation: 301 related unit, provider, and migration tests passed (one skipped); targeted regressions passed from fresh Cargo target directories.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Thom Chiovoloni (thomcc-work) added a commit that referenced this pull request Nov 2, 2026
Keep the database message in ordinary migration error display while retaining the SQLx source for SQLSTATE retry classification. Add a red/green regression that also proves failed migration statements leave the ledger, stored function, and durable rows unchanged.

State that migration 0030 must not ship before the 0027-0029 prerequisites, including the dependency of #51 on #32. Addresses review items 41-N6 and 41-N7.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Thom Chiovoloni (thomcc-work) added a commit that referenced this pull request Nov 2, 2026
Match #51's associated load_migrations and parse_version functions, including the failed-unlock regression added by #41. This keeps the standalone branch buildable and avoids E0599 when the prerequisite changes are combined.

Retain b33a3f2's connection-reuse behavior without changing pool sizing or tuning for the upstream barrier-based test. Addresses review item 41-N11.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Thom Chiovoloni (thomcc-work) added a commit to microsoft/pg_durable that referenced this pull request Nov 3, 2026
Pinned to 9ae067b, alongside the merged duroxide revision.

Changes:

- Updated the provider dependency and lockfile.
- Advanced WORKER_SCHEMA_VERSION to 4 for the bundled migrations.
- Added a 500-request backlog regression.
- Updated migration, rollout, and behavior documentation.

@tjgreen42 Todd J. Green (tjgreen42) 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.

Review by GPT-6.1 Sol.

No actionable correctness findings in this revision. Reviewed the visibility-first dequeue ordering, claim/session eligibility and locking, migration registration and validation, and starvation regression coverage.

Release coordination note: do not ship/apply migration 0029 before #32 supplies 0027/0028; a later combined build would reject that applied ledger as a non-prefix. This dependency is already documented in #41, but would also be useful in this PR description, which still calls the migration 0027.

Scope: static review at 9ae067b. No PostgreSQL integration tests were run. Local nextest validation was blocked by the resolved uuid dependency requiring Rust 1.89 while the available toolchain was 1.88.

@tjgreen42

Copy link
Copy Markdown
Contributor

Review by GPT-6.1 Sol: The PR description is stale relative to the current diff. Please update it to:

  • Refer to migration 0029, not 0027.
  • Explain the concurrent index prebuild option and clarify that the migration still takes a SHARE lock on worker_queue until transaction commit, even when reusing the index. Lock acquisition can wait indefinitely unless a deployment-session lock_timeout is configured.
  • Mention that invalid prebuilt indexes are rejected without changing the migration ledger, fetch function, or queued work.
  • Include the index-validation/reuse regression coverage, embedded migration-version uniqueness test, and companion migration diff.

The core ordering behavior and provider compatibility summary remain accurate.

@tjgreen42 Todd J. Green (tjgreen42) 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.

LGTM

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