From 5f7a0aae9b86f095e01231abd452ceb89b514426 Mon Sep 17 00:00:00 2001 From: Brandur Date: Mon, 26 Oct 2026 19:37:57 -0500 Subject: [PATCH] [rust] Prepare v0.4.0 --- rust/CHANGELOG.md | 11 +++++++++-- rust/Cargo.lock | 10 +++++----- rust/Cargo.toml | 2 +- rust/README.md | 4 ++-- rust/riverqueue-cli/Cargo.toml | 4 ++-- rust/riverqueue-test/Cargo.toml | 4 ++-- rust/riverqueue/Cargo.toml | 6 +++--- rust/riverqueue/README.md | 4 ++-- 8 files changed, 26 insertions(+), 19 deletions(-) diff --git a/rust/CHANGELOG.md b/rust/CHANGELOG.md index 38f1d573c..45edf8a4d 100644 --- a/rust/CHANGELOG.md +++ b/rust/CHANGELOG.md @@ -10,8 +10,12 @@ Changes to River for Go are recorded in the [repository changelog](../CHANGELOG. ## [Unreleased] +## [0.4.0] - 2026-10-26 + ### Added +- Extend the unstable extension API with peer work hooks, resolved insertion options, and bounded producer claims. Post-insert callbacks now include existing unique duplicates, requested metadata, and duplicate flags. [PR #1501](https://github.com/riverqueue/river/pull/1501). +- Add optional pilot hooks for single-job, bulk, and cleaner-driven deletion. Hooks run within the deletion transaction and can extend or replace the standard deletion. [PR #1502](https://github.com/riverqueue/river/pull/1502). - A worker cancels its job with a reason by returning `JobCancelError`, like River for Go's `JobCancel(err)`. Anywhere in the worker error's source chain, it cancels the job whatever attempts it has left, skips the error handler, and records `JobCancelError: ` on the attempt as Go does. `WorkOutcome::Cancel` still cancels without a reason. [PR #1504](https://github.com/riverqueue/river/pull/1504). ### Changed @@ -21,11 +25,14 @@ Changes to River for Go are recorded in the [repository changelog](../CHANGELOG. ### Fixed +- Preserve original error types through work-begin hooks and peer outcomes so error handlers can downcast them. A `JobCancelError` reported for a peer cancels it, matching worker cancellation. [PR #1501](https://github.com/riverqueue/river/pull/1501). - Fail retries that omit a saved cursor-only step, while preserving their checkpoints for recovery. Jobs with an existing step marker retain their behavior, including legacy stale cursor entries. [PR #1534](https://github.com/riverqueue/river/pull/1534). - - Replace whole top-level metadata values on SQLite, including JSON null, matching Postgres. Completed resumable cursor steps no longer run again because of stale cursor entries. [PR #1533](https://github.com/riverqueue/river/pull/1533). +- Preserve first-step resumable cursors on failure and step progress on snooze. Transactional checkpoints no longer leak into deferred updates after rollback or a failed write; rolling back a successful checkpoint write may replay earlier unpersisted steps. [PR #1521](https://github.com/riverqueue/river/pull/1521). + +### Security -- Preserve first-step resumable cursors on failure and step progress on snooze. Transactional checkpoints no longer leak into deferred updates after rollback or a failed write; rolling back a successful checkpoint write may replay earlier unpersisted steps. +- Update locked TLS and constant-time comparison dependencies (`rustls`, `rustls-webpki`, `webpki-roots`, and `ctutils`) to address security advisories. [PR #1505](https://github.com/riverqueue/river/pull/1505), [PR #1527](https://github.com/riverqueue/river/pull/1527), [PR #1521](https://github.com/riverqueue/river/pull/1521). ## [0.3.0] - 2026-10-07 diff --git a/rust/Cargo.lock b/rust/Cargo.lock index b6339108a..7809538dc 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -934,7 +934,7 @@ dependencies = [ [[package]] name = "riverqueue" -version = "0.3.0" +version = "0.4.0" dependencies = [ "anyhow", "async-trait", @@ -958,7 +958,7 @@ dependencies = [ [[package]] name = "riverqueue-cli" -version = "0.3.0" +version = "0.4.0" dependencies = [ "riverqueue", "riverqueue-migrate", @@ -970,7 +970,7 @@ dependencies = [ [[package]] name = "riverqueue-macros" -version = "0.3.0" +version = "0.4.0" dependencies = [ "proc-macro2", "quote", @@ -982,7 +982,7 @@ dependencies = [ [[package]] name = "riverqueue-migrate" -version = "0.3.0" +version = "0.4.0" dependencies = [ "serde_json", "sqlx", @@ -992,7 +992,7 @@ dependencies = [ [[package]] name = "riverqueue-test" -version = "0.3.0" +version = "0.4.0" dependencies = [ "chrono", "riverqueue", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index c9fe3dd3d..9dfef0e7e 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -15,7 +15,7 @@ homepage = "https://riverqueue.com" license = "MPL-2.0" repository = "https://github.com/riverqueue/river" rust-version = "1.95" -version = "0.3.0" +version = "0.4.0" [workspace.dependencies] async-trait = "0.1.92" diff --git a/rust/README.md b/rust/README.md index 4d4c79143..947427f64 100644 --- a/rust/README.md +++ b/rust/README.md @@ -6,7 +6,7 @@ River is a fast, reliable background job system backed by Postgres or SQLite. It ```toml [dependencies] -riverqueue = "0.3.0" +riverqueue = "0.4.0" serde = { version = "1", features = ["derive"] } serde_json = "1" tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] } @@ -23,7 +23,7 @@ Rust version is 1.95. | `chrono-tz` | no | IANA zone names such as `America/New_York` in cron `CRON_TZ=` and `TZ=` prefixes | For SQLite alone, use -`riverqueue = { version = "0.3.0", default-features = false, features = ["sqlite"] }`. +`riverqueue = { version = "0.4.0", default-features = false, features = ["sqlite"] }`. River's API uses types from SQLx (pools and transactions), Chrono (timestamps), `serde_json` (metadata, outputs, and other JSON values), and diff --git a/rust/riverqueue-cli/Cargo.toml b/rust/riverqueue-cli/Cargo.toml index fa22c9c97..16179de70 100644 --- a/rust/riverqueue-cli/Cargo.toml +++ b/rust/riverqueue-cli/Cargo.toml @@ -26,8 +26,8 @@ path = "src/main.rs" doc = false [dependencies] -riverqueue = { path = "../riverqueue", version = "=0.3.0", default-features = false } -riverqueue-migrate = { path = "../riverqueue-migrate", version = "=0.3.0", default-features = false } +riverqueue = { path = "../riverqueue", version = "=0.4.0", default-features = false } +riverqueue-migrate = { path = "../riverqueue-migrate", version = "=0.4.0", default-features = false } serde.workspace = true sqlx = { workspace = true, features = ["tls-rustls"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal"] } diff --git a/rust/riverqueue-test/Cargo.toml b/rust/riverqueue-test/Cargo.toml index c4cd207f8..052885b3b 100644 --- a/rust/riverqueue-test/Cargo.toml +++ b/rust/riverqueue-test/Cargo.toml @@ -24,12 +24,12 @@ sqlite = ["riverqueue/sqlite"] [dependencies] chrono.workspace = true -riverqueue = { path = "../riverqueue", version = "=0.3.0", default-features = false } +riverqueue = { path = "../riverqueue", version = "=0.4.0", default-features = false } serde_json.workspace = true tokio-util.workspace = true [dev-dependencies] -riverqueue-migrate = { path = "../riverqueue-migrate", version = "=0.3.0", default-features = false, features = ["sqlite"] } +riverqueue-migrate = { path = "../riverqueue-migrate", version = "=0.4.0", default-features = false, features = ["sqlite"] } serde.workspace = true sqlx.workspace = true tokio.workspace = true diff --git a/rust/riverqueue/Cargo.toml b/rust/riverqueue/Cargo.toml index 6a3d33c1a..75a709f68 100644 --- a/rust/riverqueue/Cargo.toml +++ b/rust/riverqueue/Cargo.toml @@ -31,8 +31,8 @@ base64.workspace = true chrono.workspace = true chrono-tz = { version = "0.10.4", optional = true } futures-util.workspace = true -riverqueue-migrate = { path = "../riverqueue-migrate", version = "=0.3.0", default-features = false } -riverqueue-macros = { path = "../riverqueue-macros", version = "=0.3.0" } +riverqueue-migrate = { path = "../riverqueue-migrate", version = "=0.4.0", default-features = false } +riverqueue-macros = { path = "../riverqueue-macros", version = "=0.4.0" } rand = { workspace = true } serde.workspace = true serde_json.workspace = true @@ -45,7 +45,7 @@ tracing.workspace = true [dev-dependencies] anyhow = "1.0.104" -riverqueue-migrate = { path = "../riverqueue-migrate", version = "=0.3.0", features = ["postgres", "sqlite"] } +riverqueue-migrate = { path = "../riverqueue-migrate", version = "=0.4.0", features = ["postgres", "sqlite"] } serde.workspace = true tracing-subscriber = { version = "0.3.20", default-features = false, features = ["registry", "std"] } # Fault-injection tests proxy database connections. diff --git a/rust/riverqueue/README.md b/rust/riverqueue/README.md index 6e164f411..5e5a42d7e 100644 --- a/rust/riverqueue/README.md +++ b/rust/riverqueue/README.md @@ -12,7 +12,7 @@ The [mixed deployment guide](https://docs.rs/riverqueue/latest/riverqueue/guide/ ```toml [dependencies] -riverqueue = "0.3.0" +riverqueue = "0.4.0" serde = { version = "1", features = ["derive"] } serde_json = "1" tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] } @@ -29,7 +29,7 @@ Rust version is 1.95. | `chrono-tz` | no | IANA zone names such as `America/New_York` in cron `CRON_TZ=` and `TZ=` prefixes | For SQLite alone, use -`riverqueue = { version = "0.3.0", default-features = false, features = ["sqlite"] }`. +`riverqueue = { version = "0.4.0", default-features = false, features = ["sqlite"] }`. River's API uses types from SQLx (pools and transactions), Chrono (timestamps), `serde_json` (metadata, outputs, and other JSON values), and