Skip to content

Commit 27be74b

Browse files
committed
Add fully functional Ruby client compatible with Go client
Here, try to do a full port of River to Ruby using a similar technique to Rust through repeated refinement iterations. I also had it try to go through each of River's features sections in the docs and make sure we have equivalent Ruby functionality. I changed a fair bit through manual inspection of the resulting APIs, but there's still a reasonable possibility we'll notice more things and want to make a few additional tweaks before fully committing. I also have a full Pro implementation locally, but have left it out of this change set. We'd ship this from a private gem server separately.
1 parent f29d1d4 commit 27be74b

160 files changed

Lines changed: 15043 additions & 632 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/ci.yaml‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,43 @@ env:
2323
on:
2424
- push
2525

26+
permissions:
27+
contents: read
28+
2629
jobs:
30+
verify:
31+
runs-on: ubuntu-latest
32+
timeout-minutes: 3
33+
34+
steps:
35+
- name: Checkout
36+
uses: actions/checkout@v4
37+
38+
- name: Install Ruby
39+
uses: ruby/setup-ruby@v1
40+
with:
41+
ruby-version: ${{ env.RUBY_VERSION }}
42+
43+
- name: Read upstream River revision
44+
id: river_revision
45+
run: |
46+
ruby -rjson -e '
47+
revision = JSON.parse(File.read("migration/manifest.json")).fetch("revision")
48+
abort "Invalid River revision" unless /\A[0-9a-f]{40}\z/.match?(revision)
49+
File.open(ENV.fetch("GITHUB_OUTPUT"), "a") { |file| file.puts("revision=#{revision}") }
50+
'
51+
52+
- name: Checkout upstream River
53+
uses: actions/checkout@v4
54+
with:
55+
path: upstream/river
56+
persist-credentials: false
57+
ref: ${{ steps.river_revision.outputs.revision }}
58+
repository: riverqueue/river
59+
60+
- name: Verify migrations
61+
run: make verify RIVER_PATH="$GITHUB_WORKSPACE/upstream/river"
62+
2763
gem_build:
2864
runs-on: ubuntu-latest
2965
timeout-minutes: 3
@@ -50,6 +86,10 @@ jobs:
5086
run: gem build riverqueue-sequel.gemspec
5187
working-directory: ./driver/riverqueue-sequel
5288

89+
- name: Build gem (riverqueue-rails)
90+
run: gem build riverqueue-rails.gemspec
91+
working-directory: ./rails/riverqueue-rails
92+
5393
lint:
5494
runs-on: ubuntu-latest
5595
timeout-minutes: 3
@@ -68,6 +108,10 @@ jobs:
68108
run: bundle exec standardrb
69109
working-directory: .
70110

111+
- name: Frozen string literal comments
112+
run: bundle exec rubocop --config .rubocop-frozen-string-literal.yaml --only Style/FrozenStringLiteralComment
113+
working-directory: .
114+
71115
- name: bundle install (riverqueue-activerecord)
72116
run: bundle install
73117
working-directory: ./driver/riverqueue-activerecord
@@ -195,3 +239,44 @@ jobs:
195239
- name: Rspec (riverqueue-sequel)
196240
run: bundle exec rspec
197241
working-directory: ./driver/riverqueue-sequel
242+
243+
rails:
244+
runs-on: ubuntu-latest
245+
timeout-minutes: 5
246+
strategy:
247+
matrix:
248+
include:
249+
- rails: "~> 7.2.0"
250+
ruby: "3.2"
251+
- rails: "~> 8.0.0"
252+
ruby: "3.3"
253+
- rails: "~> 8.1.0"
254+
ruby: "4.0"
255+
env:
256+
BUNDLE_FROZEN: "false"
257+
RAILS_VERSION: ${{ matrix.rails }}
258+
RIVER_REQUIRE_DATABASES: "1"
259+
services:
260+
postgres:
261+
image: postgres:17
262+
env:
263+
POSTGRES_DB: river_test
264+
POSTGRES_PASSWORD: postgres
265+
options: >-
266+
--health-cmd pg_isready
267+
--health-interval 2s
268+
--health-timeout 5s
269+
--health-retries 5
270+
ports:
271+
- 5432:5432
272+
steps:
273+
- uses: actions/checkout@v4
274+
- uses: ruby/setup-ruby@v1
275+
with:
276+
ruby-version: ${{ matrix.ruby }}
277+
- run: bundle install
278+
working-directory: ./rails/riverqueue-rails
279+
- run: bundle exec rspec
280+
working-directory: ./rails/riverqueue-rails
281+
- run: bundle exec standardrb
282+
working-directory: ./rails/riverqueue-rails

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
.DS_Store
22
*.gem
3+
/benchmarks/
34
coverage/
5+
/pro/
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
AllCops:
2+
NewCops: disable
3+
Exclude:
4+
- ".ruby-lsp/**/*"
5+
- "**/coverage/**/*"
6+
- "**/vendor/**/*"
7+
8+
Style/FrozenStringLiteralComment:
9+
Enabled: true
10+
EnforcedStyle: always

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add a full Ruby client for River with Go-compatible job insertion and execution on PostgreSQL and SQLite through ActiveRecord or Sequel. Includes workers, retries, cancellation, periodic and resumable jobs, 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).
13+
1014
## [0.11.0] - 2026-09-02
1115

1216
### Added

‎Gemfile‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# frozen_string_literal: true
2+
13
source "https://rubygems.org"
24

35
gemspec
@@ -9,9 +11,12 @@ end
911

1012
group :test do
1113
gem "debug"
14+
gem "fugit", "~> 1.13", require: false
15+
gem "minitest", require: false
1216
gem "pg"
1317
gem "rspec-core"
1418
gem "rspec-expectations"
19+
gem "riverqueue-activerecord", path: "driver/riverqueue-activerecord"
1520
gem "riverqueue-sequel", path: "driver/riverqueue-sequel"
1621
gem "simplecov", require: false
1722
gem "sqlite3"

‎Gemfile.lock‎

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,35 @@ PATH
22
remote: .
33
specs:
44
riverqueue (0.11.0)
5+
logger (> 0, < 1000)
6+
optparse (> 0, < 1000)
7+
securerandom (> 0, < 1000)
8+
timeout (> 0, < 1000)
9+
10+
PATH
11+
remote: driver/riverqueue-activerecord
12+
specs:
13+
riverqueue-activerecord (0.11.0)
14+
activerecord (> 0, < 1000)
15+
activesupport (> 0, < 1000)
16+
riverqueue (= 0.11.0)
517

618
PATH
719
remote: driver/riverqueue-sequel
820
specs:
921
riverqueue-sequel (0.11.0)
22+
riverqueue (= 0.11.0)
1023
sequel (> 0, < 1000)
1124

1225
GEM
1326
remote: https://rubygems.org/
1427
specs:
28+
activemodel (8.1.3)
29+
activesupport (= 8.1.3)
30+
activerecord (8.1.3)
31+
activemodel (= 8.1.3)
32+
activesupport (= 8.1.3)
33+
timeout (>= 0.4.0)
1534
activesupport (8.1.3)
1635
base64
1736
bigdecimal
@@ -39,9 +58,14 @@ GEM
3958
docile (1.4.1)
4059
drb (2.2.3)
4160
erb (6.0.4)
61+
et-orbi (1.4.2)
62+
tzinfo
4263
ffi (1.17.4-arm64-darwin)
4364
ffi (1.17.4-x86_64-linux-gnu)
4465
fileutils (1.8.0)
66+
fugit (1.13.0)
67+
et-orbi (~> 1.4)
68+
raabro (~> 1.4)
4569
i18n (1.14.8)
4670
concurrent-ruby (~> 1.0)
4771
io-console (0.8.2)
@@ -62,6 +86,7 @@ GEM
6286
drb (~> 2.0)
6387
prism (~> 1.5)
6488
mutex_m (0.3.0)
89+
optparse (0.8.1)
6590
parallel (1.27.0)
6691
parser (3.3.11.1)
6792
ast (~> 2.4.1)
@@ -75,6 +100,7 @@ GEM
75100
psych (5.3.1)
76101
date
77102
stringio
103+
raabro (1.5.0)
78104
racc (1.8.1)
79105
rainbow (3.1.1)
80106
rb-fsevent (0.11.2)
@@ -159,6 +185,7 @@ GEM
159185
strscan (3.1.7)
160186
terminal-table (4.0.0)
161187
unicode-display_width (>= 1.1.1, < 4)
188+
timeout (0.6.1)
162189
tsort (0.2.0)
163190
tzinfo (2.0.6)
164191
concurrent-ruby (~> 1.0)
@@ -173,8 +200,11 @@ PLATFORMS
173200

174201
DEPENDENCIES
175202
debug
203+
fugit (~> 1.13)
204+
minitest
176205
pg
177206
riverqueue!
207+
riverqueue-activerecord!
178208
riverqueue-sequel!
179209
rspec-core
180210
rspec-expectations
@@ -184,4 +214,4 @@ DEPENDENCIES
184214
steep
185215

186216
BUNDLED WITH
187-
2.6.7
217+
4.0.9

‎Makefile‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
.DEFAULT_GOAL := help
22

3+
RIVER_PATH ?= ../river
4+
35
# Looks at comments using ## on targets and uses them to produce a help output.
46
.PHONY: help
57
help: ALIGN=14
@@ -11,9 +13,11 @@ install: ## Run `bundle install` on gem and all subgems
1113
bundle install
1214
cd driver/riverqueue-activerecord && bundle install
1315
cd driver/riverqueue-sequel && bundle install
16+
cd rails/riverqueue-rails && bundle install
17+
@if [ -d pro/riverqueue-pro ]; then cd pro/riverqueue-pro && bundle install; fi
1418

1519
.PHONY: lint
16-
lint: standardrb ## Run linter (standardrb) on gem and all subgems
20+
lint: standardrb frozen-string-literals ## Run linters on gem and all subgems
1721

1822
.PHONY: rspec
1923
rspec: spec
@@ -23,12 +27,20 @@ spec:
2327
bundle exec rspec
2428
cd driver/riverqueue-activerecord && bundle exec rspec
2529
cd driver/riverqueue-sequel && bundle exec rspec
30+
cd rails/riverqueue-rails && bundle exec rspec
31+
@if [ -d pro/riverqueue-pro ]; then cd pro/riverqueue-pro && bundle exec rspec; fi
2632

2733
.PHONY: standardrb
2834
standardrb:
2935
bundle exec standardrb --fix
3036
cd driver/riverqueue-activerecord && bundle exec standardrb --fix
3137
cd driver/riverqueue-sequel && bundle exec standardrb --fix
38+
cd rails/riverqueue-rails && bundle exec standardrb --fix
39+
@if [ -d pro/riverqueue-pro ]; then cd pro/riverqueue-pro && bundle exec standardrb --fix; fi
40+
41+
.PHONY: frozen-string-literals
42+
frozen-string-literals:
43+
bundle exec rubocop --config .rubocop-frozen-string-literal.yaml --only Style/FrozenStringLiteralComment
3244

3345
.PHONY: steep
3446
steep:
@@ -45,3 +57,9 @@ update: ## Run `bundle update` on gem and all subgems
4557
bundle update
4658
cd driver/riverqueue-activerecord && bundle update
4759
cd driver/riverqueue-sequel && bundle update
60+
cd rails/riverqueue-rails && bundle update
61+
@if [ -d pro/riverqueue-pro ]; then cd pro/riverqueue-pro && bundle update; fi
62+
63+
.PHONY: verify
64+
verify: ## Verify bundled migrations against RIVER_PATH (default ../river)
65+
ruby scripts/sync_migrations.rb --check "$(RIVER_PATH)"

‎Steepfile‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1+
# frozen_string_literal: true
2+
13
D = Steep::Diagnostic
24

35
target :lib do
46
check "lib"
57

68
library "digest"
79
library "json"
10+
library "logger"
11+
library "optparse"
12+
library "securerandom"
13+
library "socket"
814
library "time"
15+
library "timeout"
916

1017
signature "sig"
1118

0 commit comments

Comments
 (0)