Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ jobs:
strategy:
matrix:
# Keep both supported Go versions covered without repeating SQLite,
# libSQL, and Turso tests for every PostgreSQL version.
# libSQL, and Turso tests for every Postgres version.
go-version: ["1.27", "1.26"]
include:
# Only the newest Go version runs with the race detector.
Expand Down Expand Up @@ -181,18 +181,18 @@ jobs:
timeout-minutes: 10

steps:
# CLI tests use each runner's bundled PostgreSQL version; the database
# test matrix above covers supported PostgreSQL versions separately.
# GitHub's Linux image includes PostgreSQL with its service disabled.
- name: Set up PostgreSQL (Linux)
# CLI tests use each runner's bundled Postgres version; the database
# test matrix above covers supported Postgres versions separately.
# GitHub's Linux image includes Postgres with its service disabled.
- name: Set up Postgres (Linux)
if: runner.os == 'Linux'
run: |
sudo systemctl start postgresql.service
sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'postgres'"
sudo -u postgres createdb river_dev

# GitHub's Windows image exposes its PostgreSQL binaries via PGBIN.
- name: Set up PostgreSQL (Windows)
# GitHub's Windows image exposes its Postgres binaries via PGBIN.
- name: Set up Postgres (Windows)
if: runner.os == 'Windows'
shell: pwsh
env:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/java.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
run: make test/java/sqlite

postgres:
name: Test (PostgreSQL ${{ matrix.postgres-version }})
name: Test (Postgres ${{ matrix.postgres-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
Expand Down Expand Up @@ -128,5 +128,5 @@ jobs:
with:
go-version-file: go.work

- name: PostgreSQL client, worker, and migration tests
- name: Postgres client, worker, and migration tests
run: make test/java/postgres
4 changes: 2 additions & 2 deletions .github/workflows/js.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 20

# The packed `node:test` suite runs its PostgreSQL tests against this
# The packed `node:test` suite runs its Postgres tests against this
# database, and RIVER_REQUIRE_POSTGRES makes them fail instead of skip
# when DATABASE_URL is missing.
services:
Expand Down Expand Up @@ -200,7 +200,7 @@ jobs:
- run: pnpm run test

test_integration:
name: Test (integration, PostgreSQL ${{ matrix.postgres-version }})
name: Test (integration, Postgres ${{ matrix.postgres-version }})
runs-on: ubuntu-latest
timeout-minutes: 20

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ruby.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
fail-fast: false
matrix:
include:
# Latest Ruby against all supported PostgreSQL versions.
# Latest Ruby against all supported Postgres versions.
- ruby: "4.0"
postgres: 18
primary: true
Expand All @@ -74,7 +74,7 @@ jobs:
- ruby: "4.0"
postgres: 14

# Older Ruby versions against the latest PostgreSQL only.
# Older Ruby versions against the latest Postgres only.
- ruby: "3.4"
postgres: 18
- ruby: "3.3"
Expand Down Expand Up @@ -192,7 +192,7 @@ jobs:
with:
ruby-version: "4.0"
working-directory: ruby/rails/riverqueue-rails
# Reuse the runner, PostgreSQL service, and installed gems across versions.
# Reuse the runner, Postgres service, and installed gems across versions.
- name: Test Rails 7.2
env:
RAILS_VERSION: "~> 7.2.0"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
with:
tool: cargo-semver-checks@0.51.0

- name: Lint, including PostgreSQL-only and SQLite-only builds
- name: Lint, including Postgres-only and SQLite-only builds
run: make lint/rust

- name: Documentation and examples
Expand Down Expand Up @@ -162,5 +162,5 @@ jobs:
go-version-file: go.work
- name: Create test database
run: PGPASSWORD=postgres createdb -h localhost -U postgres river_rust_test
- name: Rust unit, SQLite, and PostgreSQL tests
- name: Rust unit, SQLite, and Postgres tests
run: make test/rust
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- **Testing**: use require variants instead of assert.
- **Helpers**: use `Func` suffix for function variables, not `Fn`.
- **Documentation**: include comments for exported functions and types.
- **Terminology**: prefer "Postgres" over "PostgreSQL".
- **Naming**: use idiomatic Go names; see `.golangci.yaml` for allowed short variable names.

## Package Naming and Organization
Expand Down
12 changes: 6 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Fixed cancelled transaction starts leaving Turso connections unusable, which could prevent maintenance from recovering after a startup failure. [PR #1347](https://github.com/riverqueue/river/pull/1347).
- Fixed maintenance startup failures leaving a client renewing leadership with maintenance stopped in poll-only mode. After exhausting startup retries, clients now request local resignation without depending on database notifications. [PR #1347](https://github.com/riverqueue/river/pull/1347).
- Fixed `JobRescuer` overwriting jobs that complete, leave the running state, or are claimed again by another worker after being fetched for rescue, preserving their state, errors, metadata, and timestamps across PostgreSQL and SQLite drivers. Fixes [#1302](https://github.com/riverqueue/river/issues/1302). [PR #1373](https://github.com/riverqueue/river/pull/1373).
- Fixed `JobRescuer` overwriting jobs that complete, leave the running state, or are claimed again by another worker after being fetched for rescue, preserving their state, errors, metadata, and timestamps across Postgres and SQLite drivers. Fixes [#1302](https://github.com/riverqueue/river/issues/1302). [PR #1373](https://github.com/riverqueue/river/pull/1373).
- Fixed SQLite job list pagination skipping or repeating jobs by formatting cursor timestamps consistently with stored timestamps. [PR #1374](https://github.com/riverqueue/river/pull/1374).
- Improved PostgreSQL job listing performance when filtering by one finalized state (`completed`, `cancelled`, or `discarded`) and sorting by finalized time, including in River UI. [PR #1374](https://github.com/riverqueue/river/pull/1374).
- Improved Postgres job listing performance when filtering by one finalized state (`completed`, `cancelled`, or `discarded`) and sorting by finalized time, including in River UI. [PR #1374](https://github.com/riverqueue/river/pull/1374).
- Fixed `rivermigrate` leaving `river_migration` rows behind after migrating a non-main migration line down through its version 1, which caused a later up migration of that line to skip version 1. With `MigrateTx`, rows for every removed version were left behind. [PR #1378](https://github.com/riverqueue/river/pull/1378).
- Fixed `river bench` inserting every benchmark job with a `num` arg of `0` instead of numbering jobs sequentially. [PR #1379](https://github.com/riverqueue/river/pull/1379).
- Attempt errors that are valid JSON but don't have the shape River writes (for example an `at` timestamp in another format, an `attempt` stored as a string, or an `error` or `trace` that isn't a string) are now decoded on a best effort basis when reading jobs from the database. Timestamps outside RFC 3339 are left zero; stored values are unchanged. Previously a single such element made its job unreadable, and if that happened while fetching jobs, every job locked in the same fetch was left `running` indefinitely. [PR #1380](https://github.com/riverqueue/river/pull/1380).
- A fetched job whose row can't be decoded (for example a SQLite job whose `tags` were changed to something other than an array of strings) no longer leaves every job locked in the same fetch stuck `running`. The other jobs are worked normally, while the undecodable job's attempt fails with an error describing the decode failure, and it's retried or discarded like any other failed job. Its original values are preserved, with non-array `errors` values wrapped to append the failure or rescue error. Neither the rescuer nor the SQLite scheduler fails on such a job, so its retry doesn't stop other jobs from being rescued or scheduled. [PR #1380](https://github.com/riverqueue/river/pull/1380).
- Fixed SQLite notification listeners delivering notifications from before a subscription or from an unsubscribe gap. Notification reads now fetch subscribed topics in bounded batches, and cleanup deletes expired notifications in batches of 10,000 rows (reduced to 1,000 after repeated timeouts), with pauses between batches to reduce write lock contention. [PR #1381](https://github.com/riverqueue/river/pull/1381).
- Fixed the job completer panicking when a job it was finalizing had its state changed concurrently, like being moved to `pending` out of band, or being rescued while the completer's update waited on the row lock (in which case PostgreSQL returns the job's pre-update `running` row). Such jobs are now skipped without emitting a completion event. [PR #1383](https://github.com/riverqueue/river/pull/1383).
- Fixed the job completer panicking when a job it was finalizing had its state changed concurrently, like being moved to `pending` out of band, or being rescued while the completer's update waited on the row lock (in which case Postgres returns the job's pre-update `running` row). Such jobs are now skipped without emitting a completion event. [PR #1383](https://github.com/riverqueue/river/pull/1383).
- Fixed `JobList` pagination skipping or repeating jobs when ordering by `JobListOrderByTime` with multiple states. Cursors now use the same time field as the list's ordering (the one for the first listed state) rather than the one for each job's own state. Jobs where that field is null, like `finalized_at` for unfinalized jobs, are paginated correctly and consistently sort last in ascending order and first in descending order on all drivers. Ordering by `JobListOrderByTime` with an empty `States()` filter now uses `scheduled_at` instead of returning an error. [PR #1384](https://github.com/riverqueue/river/pull/1384).
- A SQLite job whose `args`, `attempted_by`, `errors`, `metadata`, or `tags` were changed to text that isn't valid JSON no longer makes every fetch from its queue fail with a "malformed JSON" error. The job's attempt fails like that of any other job that can't be decoded, and completing, rescuing, or scheduling it no longer fails either. Invalid values are left in place, except that an invalid `errors` value is kept as a string in a new array so that attempt errors can still be appended. [PR #1386](https://github.com/riverqueue/river/pull/1386).
- Fixed `UniqueOpts.ByArgs` skipping distinct jobs or failing inserts when JSON keys contain path syntax (like `user.id`), are empty, or come from unnamed tags like `json:",omitempty"`. Unaffected unique keys remain unchanged; affected jobs may be inserted again after upgrading or by old and new clients during a rolling upgrade. [PR #1387](https://github.com/riverqueue/river/pull/1387).
Expand All @@ -63,7 +63,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed the `Job appears to be stuck` log line reporting the client-level `JobTimeout` instead of the worker-level timeout when a worker overrides `Timeout`. [PR #1394](https://github.com/riverqueue/river/pull/1394).
- Fixed job cancellations received during a fetch being lost before the fetched jobs started. Matching jobs now receive cancellation before work begins. [PR #1397](https://github.com/riverqueue/river/pull/1397).
- Fixed SQLite `JobCancel` and `JobCancelTx` notifying running workers through the shared control outbox, so their contexts are cancelled when the transaction commits. [PR #1398](https://github.com/riverqueue/river/pull/1398).
- Fixed SQLite `InsertMany` and `InsertManyTx` reporting multiple inserted jobs when a batch contains the same active unique key more than once. Such batches now fail atomically, matching PostgreSQL. [PR #1399](https://github.com/riverqueue/river/pull/1399).
- Fixed SQLite `InsertMany` and `InsertManyTx` reporting multiple inserted jobs when a batch contains the same active unique key more than once. Such batches now fail atomically, matching Postgres. [PR #1399](https://github.com/riverqueue/river/pull/1399).
- Fixed error and panic handlers receiving the wrong job row when a single execution reports errors for multiple jobs. [PR #1401](https://github.com/riverqueue/river/pull/1401).
- Fixed the default retry policy scheduling a job's retry about 292 years in the past on amd64 once the job had errored 310 or more times, which made it run again immediately. The capped retry delay is now exactly the maximum duration on every architecture. [PR #1402](https://github.com/riverqueue/river/pull/1402).
- Fixed up migrations targeting an already-applied version to do nothing instead of applying later pending migrations. [PR #1403](https://github.com/riverqueue/river/pull/1403).
Expand Down Expand Up @@ -99,7 +99,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- SQLite job completion, rescue, and full-update paths now serialize timestamps using River's standard millisecond format instead of relying on database driver serialization, preventing inconsistent timestamp representations from being persisted. [PR #1353](https://github.com/riverqueue/river/pull/1353)
- SQLite drivers now return a non-nil empty `JobRow.Errors` slice for jobs without errors, matching the behavior of PostgreSQL drivers and ensuring the field serializes to `[]` instead of `null`. [PR #1354](https://github.com/riverqueue/river/pull/1354).
- SQLite drivers now return a non-nil empty `JobRow.Errors` slice for jobs without errors, matching the behavior of Postgres drivers and ensuring the field serializes to `[]` instead of `null`. [PR #1354](https://github.com/riverqueue/river/pull/1354).

## [0.44.0] - 2026-08-18

Expand Down Expand Up @@ -202,7 +202,7 @@ river migrate-get --database-url sqlite:// --version 7 --down > river7.down.sql

- Fix `JobCancel` having no effect on running jobs when using a poll-only driver (e.g. `riverdatabasesql`). The `controlActionCancel` event was silently dropped in `fetchAndRunLoop`'s `queueControlCh` handler instead of being forwarded to `maybeCancelJob`. Note: this fix only works within a single process; cross-process cancels in poll-only setups must wait for the next poll cycle. [PR #1245](https://github.com/riverqueue/river/pull/1245).
- Ensure jobs that return a custom timeout of -1 (no timeout) are never rescued. [PR #1288](https://github.com/riverqueue/river/pull/1288).
- Detect numbered PostgreSQL `REINDEX INDEX CONCURRENTLY` artifacts like `_ccnew1` and `_ccold2` so the reindexer does not keep accumulating failed artifact indexes. Fixes [#1296](https://github.com/riverqueue/river/issues/1296). [PR #1297](https://github.com/riverqueue/river/pull/1297).
- Detect numbered Postgres `REINDEX INDEX CONCURRENTLY` artifacts like `_ccnew1` and `_ccold2` so the reindexer does not keep accumulating failed artifact indexes. Fixes [#1296](https://github.com/riverqueue/river/issues/1296). [PR #1297](https://github.com/riverqueue/river/pull/1297).

## [0.39.0] - 2026-06-03

Expand Down
Loading
Loading