Repository navigation
[Rust, JS] Add pilot hooks for job deletion - #1502
Merged
Merged
Conversation
bgentry
force-pushed
the
bg/pilot-delete-hooks-rust-js
branch
2 times, most recently
from
October 13, 2026 23:41
3c84905 to
866070d
Compare
bgentry
commented
Oct 13, 2026
|
|
||
| ### Changed | ||
|
|
||
| - Job deletion through `Jobs::delete`, `Jobs::delete_many`, and the job cleaner now goes through pilot hooks, which lets a pilot replace job deletion within the same transaction, as River for Go's pilots can. Behavior without a pilot that overrides them is unchanged. [PR #1502](https://github.com/riverqueue/river/pull/1502). |
Contributor
Author
There was a problem hiding this comment.
gonna remove this, unnecessary IMO
bgentry
force-pushed
the
bg/pilot-delete-hooks-rust-js
branch
from
October 14, 2026 01:04
866070d to
73d15f3
Compare
bgentry
commented
Oct 14, 2026
Contributor
Author
There was a problem hiding this comment.
Tests in this PR went way overboard, trimming them down.
River for Rust and JavaScript delete jobs from `jobs().delete()`, `delete_many`/`deleteMany`, and the job cleaner directly, so a pilot can't take part in deletes the way it can in cancels, retries, and completions. This brings both in line with River for Go's `PilotJobDeleter`. In Rust, the `__private::Pilot` trait gains `job_delete`, `job_delete_many`, and `job_delete_before`. Each receives the deletion's transaction connection, a context with the job ID or validated parameters, and a `next` handle that runs River's standard deletion, so a pilot can substitute its own statement or make related writes in the same transaction. River errors from `next`, such as not-found or running, reach the caller unchanged. The cleaner hook runs under the cleaner's timeout and cancellation for its whole transaction, and a database error from it still counts toward the cleaner's reduced batch size. `DatabaseConnection::reborrow` is now public so a hook can run `next` and keep using the connection. In JavaScript, `PilotInterceptors` gains `delete`, `deleteMany`, and `deleteBefore`, which may call `next` or replace River's deletion, with replacement results validated like `getStuck` and `rescue`. The client routes `client.jobs.delete` and `client.jobs.deleteMany` through them in one transaction. The job cleaner runs `deleteBefore` in a new driver `maintenanceTransaction`, the same leader-fenced, batch-bounded transaction River's own cleaner uses: on Postgres the batch's statement timeout applies from the transaction's start, covering the interceptor's own statements and replacements that skip `next`, and an abort at the timeout or end of the term abandons the transaction and rejects at once. Like Go's interface, the hooks are temporarily optional: their defaults and fallbacks run River's standard deletion so behavior is unchanged, and they're documented as meant to become required once supported pilots implement them. Tests cover client and cleaner deletes through an overriding pilot inside the deletion's transaction, rollback of a failed hook including in a caller's transaction, error pass-through, unchanged behavior without overrides, and a hook's own statements before `next` ending at the cleaner's timeout, cancellation, or stop.
bgentry
force-pushed
the
bg/pilot-delete-hooks-rust-js
branch
from
October 14, 2026 01:26
73d15f3 to
8302a4e
Compare
bgentry
marked this pull request as ready for review
October 14, 2026 01:27
brandur
approved these changes
Oct 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This brings River for Rust and River for JavaScript in line with River for Go's #1500. In both, job deletion through the client's
deleteanddelete_many/deleteMany, and through the job cleaner, now goes through pilot hooks. A pilot can replace job deletion, or make related writes alongside it, within the deletion's own transaction, as it already can for cancels, retries, and completions.In Rust, the
__private::Pilottrait gainsjob_delete,job_delete_many, andjob_delete_before. Each hook receives the transaction connection, a context with the job ID or the validated parameters, and anexthandle that runs River's standard deletion. This follows the existingProducerClaimContext/ProducerClaimNextpattern. River errors fromnext, such as not-found and running-job errors, reach the caller unchanged. A database error from the cleaner hook still counts toward the cleaner's reduced batch size.DatabaseConnection::reborrowis now public, so a hook can runnextand then keep writing on the same connection.In JavaScript,
PilotInterceptorsgainsdelete,deleteMany, anddeleteBefore. LikegetStuckandrescue, they may callnextor replace River's deletion, and River validates a replacement result before accepting it. The client routesclient.jobs.deleteandclient.jobs.deleteManythrough them in one transaction. The job cleaner runsdeleteBeforeinside a new optional driver method,maintenanceTransaction, which is the same leader-fenced, batch-bounded transaction River's own cleaner uses. On Postgres, the batch's statement timeout applies from the start of that transaction, so it also bounds the interceptor's own statements and replacements that never callnext, and an abort at the timeout or at the end of the leader's term abandons the transaction and rejects right away.As in Go, the hooks are temporarily optional. The Rust trait defaults and the JavaScript fallbacks run River's standard deletion, so behavior is unchanged unless a pilot overrides them. Their docs say they're meant to become required once supported pilots implement them.