riverqueue 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b197b9ab6ebd0ca0b94b8fdde5bf071b61060c83509080fd553cf1f96f69a558
4
- data.tar.gz: 1f9b3dcf3526a1c931c6fb6bf40f32da98084836c8841a6c5447840074401b8f
3
+ metadata.gz: 1ce8622d0f151131d632d673e694e8ea90ded0502ba912274c7d044076063ee9
4
+ data.tar.gz: 1df7e4f2f10a3cfe36d3d08793a38b5400bf12dd32c3db3d3fd248184523d961
5
5
  SHA512:
6
- metadata.gz: '0782b30ebb1ba9f06886ada1518968bf988736a285164242ec5f03e0dae282b0f8e4ceb0a5cee5e2c21eb92a2ef05765ef3ae2d11451f414398b99fc5907a095'
7
- data.tar.gz: 8d1ea3397d795c6b17dd9cb55dcfa3312044240891abe3ed37f4bfd86ec8cba44a4f9b6e750754cb8824fbdc2f6c5162fad613f78b71055ae13ab34651a293e9
6
+ metadata.gz: c09ee3fefb3b0d9bdb4bd969761117470a84b7bcfa1278819446471c53348356ddffea3fa424d0cf086f57b1134ec49c1d470d03314286d21d50c9d1670568a4
7
+ data.tar.gz: a79a913f6f455f8a6a14e989ae72c415adb39248d97c1457b2cfd077b74ce41676e1f3bc79239d4a33d2653485074de7a8a6fd414699fec2e30b97c1fedb3d11
data/CHANGELOG.md CHANGED
@@ -7,11 +7,87 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.14.0] - 2026-10-26
11
+
12
+ ### Added
13
+
14
+ - Receive Postgres and SQLite notifications for insertions, queue controls, cancellation, and leadership handoffs, with reconnect recovery and a `poll_only` option. [PR #1496](https://github.com/riverqueue/river/pull/1496).
15
+ - Add `Client#request_resign` to request that the maintenance leader relinquish leadership after the caller's transaction commits. [PR #1496](https://github.com/riverqueue/river/pull/1496).
16
+ - Allow `River::Workers#add` to register a kind and a work block, using the client's default retry and timeout policies. [PR #1486](https://github.com/riverqueue/river/pull/1486).
17
+ - Added `Client#job_complete_tx(job)` to complete a running job in the caller's Active Record or Sequel transaction, including pending metadata and output. An active transaction on the driver's connection is required. Completion rolls back with the transaction; once committed, it takes precedence over subsequent worker errors and emits a completion event when the worker finishes. [PR #1490](https://github.com/riverqueue/river/pull/1490).
18
+
19
+ ### Changed
20
+
21
+ - River operations called inside an open Active Record or Sequel transaction now run in that transaction and open no savepoint of their own. If an operation raises, roll back the transaction, or wrap the call in your own savepoint to recover and continue. A `driver.rollback_exception` raised inside `Driver#transaction` now reaches the enclosing transaction block, as a rollback raised in your own code would. Before, it rolled back only River's savepoint. Set `RIVER_USE_LEGACY_SUBTRANSACTIONS=1` (or `true`) to restore the savepoints. This temporary fallback will be removed in a future release. [PR #1544](https://github.com/riverqueue/river/pull/1544).
22
+ - `work_end(job, error)` hooks now return the attempt's error, matching Go. Return the incoming error to preserve it, a replacement exception to change it, or `nil` to clear a failure. The return value feeds the next hook in registration order. Existing observing hooks must explicitly return `error`. End hooks are skipped if `work_begin` raises or the worker raises an exception outside `StandardError`. [PR #1520](https://github.com/riverqueue/river/pull/1520).
23
+
24
+ ### Fixed
25
+
26
+ - The scheduler no longer opens a savepoint for each due job to catch unique key conflicts. A pass that made more than 64 jobs available overflowed the Postgres subtransaction cache, which can slow queries across the server. The scheduler now finds conflicts with one statement on Postgres and checks before each write on SQLite. Conflicting jobs are still discarded with `unique_key_conflict: scheduler_discarded` metadata. On Postgres, the scheduler now waits for a due job that another transaction has locked, instead of skipping it. [PR #1544](https://github.com/riverqueue/river/pull/1544).
27
+ - Default periodic jobs to their occurrence time, preserving constructor and argument-level schedules. [PR #1537](https://github.com/riverqueue/river/pull/1537).
28
+ - 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).
29
+ - Support large SQLite metadata updates without reaching the expression-depth limit, preserving top-level replacement and JSON null values. [PR #1533](https://github.com/riverqueue/river/pull/1533).
30
+ - A `River::Config` without an explicit `id:` generates its default client ID on first use in each process, so clients built before a fork (as with preloading Puma, Unicorn, or Pitchfork servers) no longer share one ID across forked workers. Explicit IDs are unchanged, and `Config#with` copies share the original's ID. [PR #1498](https://github.com/riverqueue/river/pull/1498).
31
+ - Inserting a job stores its encoded args as given instead of decoding and re-encoding them in Ruby, which rewrote numbers like `1.10` as `1.1` and `1e3` as `1000.0` and rounded digits beyond `Float` precision. Postgres applies its usual `jsonb` normalization, and SQLite keeps the encoded bytes, matching River's Go drivers. Affects Active Record on Postgres and SQLite, and Sequel on SQLite. [PR #1503](https://github.com/riverqueue/river/pull/1503).
32
+ - Wake workers when scheduled jobs become available or jobs are manually retried, including workers in other clients. [PR #1496](https://github.com/riverqueue/river/pull/1496).
33
+ - Honor cancellations that arrive between claiming a job and starting its worker. [PR #1496](https://github.com/riverqueue/river/pull/1496).
34
+ - Preserve worker wakeups that arrive between a fetch and the producer going to sleep. [PR #1496](https://github.com/riverqueue/river/pull/1496).
35
+
36
+ ## [0.13.0] - 2026-10-08
37
+
38
+ ### Added
39
+
40
+ - Expanded checks against Go-generated conformance fixtures to cover cron schedules, snooze counters, all shared metadata keys, and queue-control and leadership notification emission through both SQL drivers. [PR #1463](https://github.com/riverqueue/river/pull/1463).
41
+ - Added `CRON_TZ=` / `TZ=` prefixes, `?` wildcards, and Go-style `@every` durations to `PeriodicCron`. [PR #1463](https://github.com/riverqueue/river/pull/1463).
42
+
43
+ ### Changed
44
+
45
+ - Ruby is now developed in the main [River repository](https://github.com/riverqueue/river/tree/master/ruby). Gem names and require paths are unchanged. The four public gems (`riverqueue`, `riverqueue-activerecord`, `riverqueue-sequel`, and `riverqueue-rails`) are released together. [PR #1463](https://github.com/riverqueue/river/pull/1463).
46
+ - Job insertion accepts only `available`, `pending`, and `scheduled` states. `running`, `retryable`, and terminal states are rejected, including when set by insertion hooks. [PR #1463](https://github.com/riverqueue/river/pull/1463).
47
+ - Insertion rejects queue names containing characters other than ASCII letters, digits, underscores, hyphens, colons, or periods. Nonzero `UniqueOpts#by_period` values must be at least one second. [PR #1463](https://github.com/riverqueue/river/pull/1463).
48
+ - Attempt counts must be between 0 and 32,767, and `max_attempts` must be between 1 and 32,767. These bounds also apply on SQLite. `job_retry` raises `ArgumentError` when another attempt would exceed the limit. [PR #1463](https://github.com/riverqueue/river/pull/1463).
49
+ - Job and queue metadata updates require a Hash; JSON-encoded strings are no longer accepted. Pass an empty Hash to clear metadata. Updates to `attempted_by` require string entries. [PR #1463](https://github.com/riverqueue/river/pull/1463).
50
+
51
+ ### Fixed
52
+
53
+ - Externally claimed jobs honor worker retry hooks, including Active Job's retry policy, and use their claim timestamps for queue-wait statistics and attempt errors. Worker initialization failures are logged without losing the reported work error. [PR #1463](https://github.com/riverqueue/river/pull/1463).
54
+ - Externally reported cancellation, snooze, and interruption signals follow normal worker finalization instead of being recorded as ordinary failures. [PR #1463](https://github.com/riverqueue/river/pull/1463).
55
+ - Graceful shutdown and queue removal continue observing remote cancellation until active jobs finish, including when worker timeouts are disabled or cancellation polling temporarily fails. Draining waits respect polling intervals and wake when the last attempt finishes. [PR #1463](https://github.com/riverqueue/river/pull/1463).
56
+ - Blocking lifecycle calls from the client's own runtime threads fail immediately instead of waiting for themselves. Workers can still request nonblocking stop. [PR #1463](https://github.com/riverqueue/river/pull/1463).
57
+ - Inserts reject states other than `available`, `pending`, and `scheduled`, preventing stranded `running` jobs without attempt timestamps. Insertion hooks are checked after all callbacks run, and invalid batches roll back hook writes. [PR #1463](https://github.com/riverqueue/river/pull/1463).
58
+ - The Sequel driver preserves application `ArgumentError` exceptions raised inside SQLite transactions after rolling back, including validation errors from insertion hooks. [PR #1463](https://github.com/riverqueue/river/pull/1463).
59
+ - Job inserts and updates reject attempt limits above 32,767 consistently across databases. Attempt updates and manual retries enforce the portable counter range, and claims tolerate counters already at the limit. [PR #1463](https://github.com/riverqueue/river/pull/1463).
60
+ - Wildcard queue pause and resume publish events for every affected queue, including beyond 100 queues. Events use the update's snapshots so concurrent changes cannot replace their contents or introduce unrelated queues. [PR #1463](https://github.com/riverqueue/river/pull/1463).
61
+ - Manually retrying a cancelled job clears the old cancellation request so its next attempt can complete. [PR #1463](https://github.com/riverqueue/river/pull/1463).
62
+ - Cancellation wins atomically over discarded attempts and other state transitions, including the last attempt or a worker that disables retries. [PR #1463](https://github.com/riverqueue/river/pull/1463).
63
+ - Stuck-job rescue falls back to the default retry policy per job when an application policy fails or returns an invalid time, allowing recovery and cleanup to continue. [PR #1463](https://github.com/riverqueue/river/pull/1463).
64
+ - Clients without consumer queues run configured periodic jobs and maintenance services. Adding periodic jobs starts maintenance when needed; registration is rejected when leader election is disabled. [PR #1463](https://github.com/riverqueue/river/pull/1463).
65
+ - Bulk deletion excludes running jobs before applying its limit and locks eligible Postgres rows so concurrent retries cannot cause deletion of jobs that no longer match the filters. [PR #1463](https://github.com/riverqueue/river/pull/1463).
66
+ - Stuck-job rescue respects longer or disabled client and worker timeouts and scans past protected attempts without consuming the rescue limit. [PR #1463](https://github.com/riverqueue/river/pull/1463).
67
+ - Snoozing and rescue tolerate JSON counters that overflow SQLite's floating-point representation. [PR #1463](https://github.com/riverqueue/river/pull/1463).
68
+ - Snoozing tolerates nonnumeric metadata counters instead of failing on booleans or collections. Ruby-specific recovery cases are tested independently of the shared Go fixtures. [PR #1463](https://github.com/riverqueue/river/pull/1463).
69
+ - Periodic jobs now carry `periodic: true` and, when named, `river:periodic_job_id`, while preserving constructor options and application metadata. [PR #1463](https://github.com/riverqueue/river/pull/1463).
70
+ - Queue pause, resume, metadata changes, and leader resignation now broadcast notifications for clients in other languages. Notifications commit and roll back with the corresponding database change. [PR #1463](https://github.com/riverqueue/river/pull/1463).
71
+ - Cron schedules include both occurrences of repeated daylight-saving times when given a local reference time. [PR #1463](https://github.com/riverqueue/river/pull/1463).
72
+ - Job insertion rejects invalid queue names, nonpositive attempt limits, and nonzero uniqueness periods shorter than one second before writing any jobs. [PR #1463](https://github.com/riverqueue/river/pull/1463).
73
+ - Custom maintenance service failures are logged without blocking other services, stuck-job rescue, or cleanup. [PR #1463](https://github.com/riverqueue/river/pull/1463).
74
+ - Job updates reject non-object metadata before writing to the database, preserving the existing job when invalid metadata is supplied. [PR #1463](https://github.com/riverqueue/river/pull/1463).
75
+ - Job completion atomically checks for cancellation so a concurrent cancellation cannot be overwritten by completion, including when finalization hooks are configured. [PR #1463](https://github.com/riverqueue/river/pull/1463).
76
+ - Job updates reject nonpositive attempt limits consistently on Postgres and SQLite. [PR #1463](https://github.com/riverqueue/river/pull/1463).
77
+ - Job lifecycle events report worker execution and completion durations separately using a monotonic clock. [PR #1463](https://github.com/riverqueue/river/pull/1463).
78
+ - Finalization hooks that delete jobs honor concurrent cancellation and record the cancelled attempt instead of deleting it. [PR #1463](https://github.com/riverqueue/river/pull/1463).
79
+ - Queue metadata writes and job metadata merges reject non-object values before changing persisted data. Job updates also reject non-string worker IDs in attempt histories. [PR #1463](https://github.com/riverqueue/river/pull/1463).
80
+ - Unique inserts with `exclude_kind` preserve the existing job's kind when a different kind conflicts, on both databases and through both drivers. [PR #1463](https://github.com/riverqueue/river/pull/1463).
81
+ - Retrying, snoozing, and interrupting jobs preserve the original queue-wait duration in lifecycle events. [PR #1463](https://github.com/riverqueue/river/pull/1463).
82
+ - Invalid rescue counters no longer prevent other stuck jobs in the batch from being rescued. [PR #1463](https://github.com/riverqueue/river/pull/1463).
83
+ - SQLite retains only the newest 100 worker IDs when claiming a job, matching Postgres. [PR #1463](https://github.com/riverqueue/river/pull/1463).
84
+ - Attempt-error serialization supports frozen timestamps and preserves the caller's timezone. [PR #1463](https://github.com/riverqueue/river/pull/1463).
85
+
10
86
  ## [0.12.0] - 2026-10-01
11
87
 
12
88
  ### Added
13
89
 
14
- - Add a full Ruby client for River with Go-compatible job insertion and execution on PostgreSQL, SQLite, and YugabyteDB through ActiveRecord or Sequel. Includes workers, retries, cancellation, periodic and resumable jobs, job-persisted logging, job administration, migration and worker CLIs, and testing helpers. Rails and Active Job integration is available through `riverqueue-rails`, with workflows, batches, sequences, concurrency controls, and other advanced features in the separately distributed `riverqueue-pro` gem. [PR #70](https://github.com/riverqueue/riverqueue-ruby/pull/70).
90
+ - Add a full Ruby client for River with Go-compatible job insertion and execution on Postgres, SQLite, and YugabyteDB through ActiveRecord or Sequel. Includes workers, retries, cancellation, periodic and resumable jobs, job-persisted logging, job administration, migration and worker CLIs, and testing helpers. Rails and Active Job integration is available through `riverqueue-rails`, with workflows, batches, sequences, concurrency controls, and other advanced features in the separately distributed `riverqueue-pro` gem. [PR #70](https://github.com/riverqueue/riverqueue-ruby/pull/70).
15
91
 
16
92
  ## [0.11.0] - 2026-09-02
17
93
 
@@ -21,7 +97,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
21
97
 
22
98
  ### Changed
23
99
 
24
- - Stop pulling in `pg` as a hard dependency of either driver. Applications now select their database adapter by including `pg` for PostgreSQL or `sqlite3` for SQLite. [PR #67](https://github.com/riverqueue/riverqueue-ruby/pull/67).
100
+ - Stop pulling in `pg` as a hard dependency of either driver. Applications now select their database adapter by including `pg` for Postgres or `sqlite3` for SQLite. [PR #67](https://github.com/riverqueue/riverqueue-ruby/pull/67).
25
101
 
26
102
  ## [0.10.1] - 2026-04-09
27
103
 
@@ -80,7 +156,7 @@ Users should upgrade backends to River v0.12.0 before upgrading this library in
80
156
 
81
157
  This updated implementation is significantly faster due to the removal of advisory locks in favor of an index-backed uniqueness system, while allowing some flexibility in which job states are considered. However, not all states may be removed from consideration when using the `by_state` option; pending, scheduled, available, and running states are required whenever customizing this list. [PR #32](https://github.com/riverqueue/riverqueue-ruby/pull/32).
82
158
 
83
- - Update REXML dependency. [PR #28](https://github.com/riverqueue/riverqueue-ruby/pull/36).
159
+ - Update REXML dependency. [PR #36](https://github.com/riverqueue/riverqueue-ruby/pull/36).
84
160
 
85
161
  ## [0.7.0] - 2024-08-30
86
162
 
@@ -105,7 +181,7 @@ Users should upgrade backends to River v0.12.0 before upgrading this library in
105
181
  ### Changed
106
182
 
107
183
  - Tag format is now checked on insert. Tags should be no more than 255 characters and match the regex `/\A[\w][\w\-]+[\w]\z/`. [PR #22](https://github.com/riverqueue/riverqueue-ruby/pull/22).
108
- - Returned jobs now have a `metadata` property. [PR #21](https://github.com/riverqueue/riverqueue-ruby/pull/22).
184
+ - Returned jobs now have a `metadata` property. [PR #22](https://github.com/riverqueue/riverqueue-ruby/pull/22).
109
185
 
110
186
  ## [0.4.0] - 2024-04-28
111
187
 
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # River for Ruby
2
+
3
+ River is a fast, reliable background job system backed by Postgres or SQLite. The Ruby client inserts and works jobs using the same database schema and job protocol as River's other languages. It includes Active Record and Sequel drivers, plus Rails and Active Job integration.
4
+
5
+ ## Installation
6
+
7
+ Ruby 3.2 or newer is required. Add a River driver and its database adapter to your application's `Gemfile`; the driver brings in the core `riverqueue` gem:
8
+
9
+ ```ruby
10
+ gem "riverqueue-sequel"
11
+ gem "pg"
12
+ ```
13
+
14
+ Use `riverqueue-activerecord` for Active Record, or `sqlite3` instead of `pg` for SQLite. Install the gems with `bundle install`. Rails applications can use [`riverqueue-rails`](rails/riverqueue-rails/README.md) to configure River as their Active Job backend.
15
+
16
+ ## Quick start
17
+
18
+ Set `DATABASE_URL` to an existing application database and apply River's migrations before inserting or working jobs:
19
+
20
+ ```sh
21
+ export DATABASE_URL=postgres://localhost/my_app
22
+ bundle exec river migrate-up
23
+ ```
24
+
25
+ Define job arguments and a worker with the same stable kind, register the worker, and insert a job. Save this as `worker.rb`:
26
+
27
+ ```ruby
28
+ require "riverqueue-sequel"
29
+
30
+ class SendEmailArgs
31
+ def initialize(address:)
32
+ @address = address
33
+ end
34
+
35
+ def kind = "send_email"
36
+ def to_json = JSON.generate(address: @address)
37
+ end
38
+
39
+ class SendEmailWorker
40
+ def self.kind = "send_email"
41
+
42
+ def work(job)
43
+ puts "Sending email to #{job.args.fetch("address")}"
44
+ job.output = {delivered: true}
45
+ end
46
+ end
47
+
48
+ db = Sequel.connect(ENV.fetch("DATABASE_URL"), max_connections: 12)
49
+ client = River::Client.new(
50
+ River::Driver::Sequel.new(db),
51
+ config: River::Config.new(
52
+ queues: {default: 10},
53
+ workers: River::Workers.new.add(SendEmailWorker)
54
+ )
55
+ )
56
+
57
+ begin
58
+ client.start
59
+ result = client.insert(SendEmailArgs.new(address: "person@example.com"))
60
+ puts "Inserted job #{result.job.id}; press Ctrl-C to stop"
61
+ sleep
62
+ rescue Interrupt
63
+ # Stop fetching and wait for active jobs before closing the database pool.
64
+ ensure
65
+ client.stop
66
+ db.disconnect
67
+ end
68
+ ```
69
+
70
+ Run `bundle exec ruby worker.rb`. Replace the worker body with your mail service. Job arguments implement `kind` and `to_json`; workers read decoded JSON keys as strings. Services sharing a job must agree on its kind and JSON fields. For SQLite and alternate Postgres schemas, see [migrations](docs/migrations.md).
71
+
72
+ A client without configured queues can insert jobs without starting worker threads. Applications own their database pools and should close them only after stopping River.
73
+
74
+ ## Transactions and other features
75
+
76
+ Inserts join a transaction opened on the same Sequel database or Active Record connection, so jobs commit or roll back with the application writes that caused them. See [transactional enqueueing](docs/README.md#transactional-enqueueing) for examples.
77
+
78
+ - [Bulk insertion](docs/README.md#bulk-insertion), [scheduled jobs](docs/README.md#scheduled-jobs), and [unique jobs](docs/README.md#unique-jobs).
79
+ - [Retries](docs/README.md#job-retries), [cancellation](docs/README.md#cancelling-jobs), and [snoozing](docs/README.md#snoozing-jobs).
80
+ - [Multiple queues](docs/README.md#multiple-queues), [periodic jobs](docs/README.md#periodic-jobs), and [resumable jobs](docs/README.md#resumable-jobs).
81
+ - [Event subscriptions](docs/README.md#subscriptions) and [job administration](docs/README.md#job-administration).
82
+ - [Graceful stopping](docs/README.md#stopping-gracefully) and a foreground [worker command](docs/workers.md).
83
+ - [Testing helpers](docs/testing.md) for application jobs and workers.
84
+
85
+ ## Documentation
86
+
87
+ See the [usage and configuration guide](docs/README.md), [migration guide](docs/migrations.md), and [Rails and Active Job integration](rails/riverqueue-rails/README.md). The [Sidekiq migration guide](docs/migrating_from_sidekiq.md) covers moving an existing application.
88
+
89
+ ## Development
90
+
91
+ See [developing River for Ruby](docs/development.md).