Skip to content

[Rust, JS] Add pilot hooks for job deletion - #1502

Merged
bgentry merged 1 commit into
masterfrom
bg/pilot-delete-hooks-rust-js
Oct 14, 2026
Merged

bgentry merged 1 commit into
masterfrom
bg/pilot-delete-hooks-rust-js

Conversation

@bgentry

@bgentry bgentry commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

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 delete and delete_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::Pilot trait gains job_delete, job_delete_many, and job_delete_before. Each hook receives the transaction connection, a context with the job ID or the validated parameters, and a next handle that runs River's standard deletion. This follows the existing ProducerClaimContext/ProducerClaimNext pattern. River errors from next, 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::reborrow is now public, so a hook can run next and then keep writing on the same connection.

In JavaScript, PilotInterceptors gains delete, deleteMany, and deleteBefore. Like getStuck and rescue, they may call next or replace River's deletion, and River validates a replacement result before accepting it. The client routes client.jobs.delete and client.jobs.deleteMany through them in one transaction. The job cleaner runs deleteBefore inside 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 call next, 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.

@bgentry
bgentry force-pushed the bg/pilot-delete-hooks-rust-js branch 2 times, most recently from 3c84905 to 866070d Compare October 13, 2026 23:41
Comment thread rust/CHANGELOG.md Outdated

### 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).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

gonna remove this, unnecessary IMO

@bgentry
bgentry force-pushed the bg/pilot-delete-hooks-rust-js branch from 866070d to 73d15f3 Compare October 14, 2026 01:04

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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
bgentry force-pushed the bg/pilot-delete-hooks-rust-js branch from 73d15f3 to 8302a4e Compare October 14, 2026 01:26
@bgentry
bgentry marked this pull request as ready for review October 14, 2026 01:27
@bgentry
bgentry requested a review from brandur October 14, 2026 01:27
@bgentry
bgentry merged commit a885ab1 into master Oct 14, 2026
44 checks passed
@bgentry
bgentry deleted the bg/pilot-delete-hooks-rust-js branch October 14, 2026 04:55
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