solid-jobs 0.1.3 → 0.4.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 +4 -4
- data/CHANGELOG.md +73 -4
- data/README.md +149 -118
- data/docs/reliability.md +73 -91
- data/exe/solid-jobs +2 -3
- data/lib/active_job/queue_adapters/solid_jobs_adapter.rb +7 -8
- data/lib/solid_jobs/{config.rb → blueprint.rb} +51 -51
- data/lib/solid_jobs/catalog.rb +427 -0
- data/lib/solid_jobs/claim.rb +315 -0
- data/lib/solid_jobs/{server.rb → conductor.rb} +10 -10
- data/lib/solid_jobs/{cli.rb → console.rb} +12 -9
- data/lib/solid_jobs/{processor.rb → engine.rb} +33 -33
- data/lib/solid_jobs/errors.rb +1 -1
- data/lib/solid_jobs/executor.rb +34 -0
- data/lib/solid_jobs/failure_policy.rb +98 -0
- data/lib/solid_jobs/heartbeat.rb +15 -13
- data/lib/solid_jobs/integrity_check.rb +39 -36
- data/lib/solid_jobs/interceptor_registry.rb +57 -0
- data/lib/solid_jobs/keyspace.rb +42 -0
- data/lib/solid_jobs/{testing.rb → lab.rb} +19 -19
- data/lib/solid_jobs/publisher.rb +186 -0
- data/lib/solid_jobs/rails_adapter.rb +13 -0
- data/lib/solid_jobs/{rails.rb → railtie.rb} +1 -2
- data/lib/solid_jobs/recovery.rb +8 -7
- data/lib/solid_jobs/task.rb +147 -0
- data/lib/solid_jobs/{scheduler.rb → timer.rb} +8 -8
- data/lib/solid_jobs/utilities.rb +5 -11
- data/lib/solid_jobs/version.rb +1 -1
- data/lib/solid_jobs.rb +28 -27
- metadata +19 -18
- data/lib/solid_jobs/active_job.rb +0 -16
- data/lib/solid_jobs/api.rb +0 -457
- data/lib/solid_jobs/client.rb +0 -202
- data/lib/solid_jobs/fetch.rb +0 -310
- data/lib/solid_jobs/job.rb +0 -156
- data/lib/solid_jobs/middleware/chain.rb +0 -104
- data/lib/solid_jobs/retry_service.rb +0 -100
- data/lib/solid_jobs/worker.rb +0 -35
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f95c0daf98dbfa77203eaa6d182f0b0a5ce4c22738a29f7d81b587c9f3abe3a
|
|
4
|
+
data.tar.gz: bf5524aa572a45f439732ec30e5ad12d5ad25b37a98462381d39bd90b5dd7c91
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cecbfb4efd3abe1598e66b1764ca07da25e4d103c5e59b66c14f84f5f8f3af6b45e91710d535b0b15ee69636a9396629a0e980451202f390a8aebb8a6b41091b
|
|
7
|
+
data.tar.gz: cf40a09b495d1ea62e0789ea8688b530b26bfc7414e77cd2d4cc30f8c874c1a8f6c19b20f2eb2c493c8ca27bbeb2a319a62024dff639d6748d720b1ab13c04d6
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,73 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.4.0] - 2026-10-03
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Keep the independent SolidJobs runtime, envelope, `solid_jobs:` keyspace,
|
|
10
|
+
interceptors, claims, and renamed component vocabulary from 0.3.0.
|
|
11
|
+
- Remaining shared names with other Ruby job libraries are limited to
|
|
12
|
+
`version.rb`, Rails Active Job adapter contracts (`ActiveJob`,
|
|
13
|
+
`QueueAdapters`, `enqueue_at`), and generic Ruby methods.
|
|
14
|
+
|
|
15
|
+
## [0.3.0] - 2026-10-03
|
|
16
|
+
|
|
17
|
+
### Breaking
|
|
18
|
+
|
|
19
|
+
- Rename the runtime components to SolidJobs-specific names:
|
|
20
|
+
`Config` to `Blueprint`, `Server` to `Conductor`, `Processor` to `Engine`,
|
|
21
|
+
`CLI` to `Console`, `Testing` to `Lab`, and `Metrics` to `Counters`.
|
|
22
|
+
- Rename the task execution callback from `perform` to `execute_task`.
|
|
23
|
+
- Rename `Task.enqueue_at` to `Task.schedule_at`. The Active Job adapter keeps
|
|
24
|
+
its Rails-required `enqueue_at` method.
|
|
25
|
+
- Rename the Active Job execution task from `ActiveJob::Wrapper` to
|
|
26
|
+
`RailsAdapter::AdapterTask`.
|
|
27
|
+
- Rename generic implementation files to match the new component vocabulary.
|
|
28
|
+
`version.rb` remains unchanged as the standard Ruby gem version entry point.
|
|
29
|
+
- Remove the remaining generic internal constants `ClassMethods`,
|
|
30
|
+
`EmptyQueueError`, and `Shutdown` in favor of `TaskMethods`,
|
|
31
|
+
`NoCapturedTask`, and `ExecutionHalt`.
|
|
32
|
+
- Replace `Node#quiet`, `Node#stop`, and `Node#dump_threads` with
|
|
33
|
+
`Node#request_control(:pause)`, `:shutdown`, or `:backtraces`.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Update the executable, Rails adapter, documentation, benchmarks, and test
|
|
38
|
+
suite to use the new vocabulary consistently.
|
|
39
|
+
- Keep the SolidJobs task API, envelope, `solid_jobs:` Redis keyspace, claims,
|
|
40
|
+
interceptors, and failure model introduced in 0.2.0.
|
|
41
|
+
- Convert configuration keys using Ruby hash transformations, preserving
|
|
42
|
+
nested values and leaving the original input unchanged.
|
|
43
|
+
|
|
44
|
+
## [0.2.0] - 2026-10-03
|
|
45
|
+
|
|
46
|
+
### Breaking
|
|
47
|
+
|
|
48
|
+
- Replace the previous job API with the independent `SolidJobs::Task` API:
|
|
49
|
+
`enqueue`, `enqueue_after`, `schedule_at`, `enqueue_many`, `execute`, and
|
|
50
|
+
`with_options`.
|
|
51
|
+
- Replace the previous payload with a SolidJobs envelope using `id`, `task`,
|
|
52
|
+
`arguments`, `channel`, `run_at`, `created_ms`, and `queued_ms`.
|
|
53
|
+
- Move all Redis data into the `solid_jobs:` keyspace. Existing queued data is
|
|
54
|
+
not read or migrated automatically.
|
|
55
|
+
- Replace middleware chains with `publish_interceptors` and
|
|
56
|
+
`execute_interceptors`, whose interceptors implement `around(context)`.
|
|
57
|
+
- Replace the administrative API with `Counters`, `Channel`, `StoredTask`,
|
|
58
|
+
`PlannedTasks`, `RetryingTasks`, `DiscardedTasks`, `Node`, `Nodes`,
|
|
59
|
+
`Execution`, and `Claims`.
|
|
60
|
+
- Replace queue configuration with channels and the `:weighted`, `:priority`,
|
|
61
|
+
and `:shuffle` ordering modes.
|
|
62
|
+
- Remove all Sidekiq compatibility aliases and wire-format compatibility.
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
|
|
66
|
+
- Claims use UUID task IDs and claim tokens, with generation-fenced completion
|
|
67
|
+
and requeue operations.
|
|
68
|
+
- Failure handling uses `max_failures`, `retry_within`, `retry_delay`, and
|
|
69
|
+
`after_final_failure`.
|
|
70
|
+
- Lab modes are now `:capture` and `:execute`.
|
|
71
|
+
|
|
5
72
|
## [0.1.3] - 2026-10-01
|
|
6
73
|
|
|
7
74
|
### Changed
|
|
@@ -13,9 +80,9 @@ All notable changes to this project will be documented in this file.
|
|
|
13
80
|
|
|
14
81
|
### Added
|
|
15
82
|
|
|
16
|
-
- `
|
|
83
|
+
- `Conductor#start` logs a warning on Ruby < 4 when `concurrency > 1`, pointing
|
|
17
84
|
to the Ruby 3.4 Ractor GC-barrier deadlock and the recommended setups.
|
|
18
|
-
- `
|
|
85
|
+
- `Conductor#stop` is bounded: components get `shutdown_timeout + STOP_GRACE`
|
|
19
86
|
to return, `:stop` is re-sent up to `STOP_RESENDS` times, then the
|
|
20
87
|
component is abandoned with an error log instead of hanging shutdown.
|
|
21
88
|
- `test/support/ractor_barrier_repro.rb`: standalone reproducer of the Ruby
|
|
@@ -23,7 +90,7 @@ All notable changes to this project will be documented in this file.
|
|
|
23
90
|
|
|
24
91
|
### Changed
|
|
25
92
|
|
|
26
|
-
-
|
|
93
|
+
- Conductor-based stress tests are skipped on Ruby < 4: Ruby 3.4's Ractor
|
|
27
94
|
scheduler deadlocks the VM on a GC barrier under cross-Ractor `move:`
|
|
28
95
|
traffic. Multi-Ractor servers are recommended on Ruby ≥ 4.0 (see
|
|
29
96
|
`docs/reliability.md`). CI jobs now time out after 20 minutes.
|
|
@@ -46,7 +113,7 @@ All notable changes to this project will be documented in this file.
|
|
|
46
113
|
|
|
47
114
|
### Added
|
|
48
115
|
|
|
49
|
-
- Ractor-oriented client,
|
|
116
|
+
- Ractor-oriented client, Engine, Scheduler, Heartbeat, and Conductor runtime.
|
|
50
117
|
- Sidekiq-compatible Redis queue keys and open-source job payload format.
|
|
51
118
|
- Immediate, scheduled, retry, and dead-job handling.
|
|
52
119
|
- At-least-once reservations with atomic journaling, generation-fenced ACK
|
|
@@ -61,6 +128,8 @@ All notable changes to this project will be documented in this file.
|
|
|
61
128
|
- Reliable-hot-path and CPU-scaling profilers plus the independent Sidekiq
|
|
62
129
|
comparison benchmark.
|
|
63
130
|
|
|
131
|
+
[0.3.0]: https://github.com/nicolasva/solid-jobs/compare/v0.2.0...v0.3.0
|
|
132
|
+
[0.2.0]: https://github.com/nicolasva/solid-jobs/compare/v0.1.3...v0.2.0
|
|
64
133
|
[0.1.3]: https://github.com/nicolasva/solid-jobs/compare/v0.1.2...v0.1.3
|
|
65
134
|
[0.1.2]: https://github.com/nicolasva/solid-jobs/compare/v0.1.1...v0.1.2
|
|
66
135
|
[0.1.1]: https://github.com/nicolasva/solid-jobs/compare/v0.1.0...v0.1.1
|
data/README.md
CHANGED
|
@@ -1,164 +1,195 @@
|
|
|
1
1
|
# SolidJobs
|
|
2
2
|
|
|
3
3
|
[](https://github.com/nicolasva/solid-jobs/actions/workflows/ci.yml)
|
|
4
|
-
[](https://codeclimate.com/github/nicolasva/solid-jobs)
|
|
5
4
|
[](https://rubygems.org/gems/solid-jobs)
|
|
6
|
-
[](https://www.rubydoc.info/gems/solid-jobs)
|
|
7
|
-
[](https://rubygems.org/gems/solid-jobs)
|
|
8
5
|
|
|
9
|
-
SolidJobs is a Ractor-oriented Redis
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
SolidJobs is a Ractor-oriented Redis task runner for Ruby. It provides its own
|
|
7
|
+
task API, Redis envelope, keyspace, interceptor model, failure policy, and
|
|
8
|
+
inspection API.
|
|
12
9
|
|
|
13
|
-
SolidJobs is
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
SolidJobs and its required gems use pure Ruby and do not require native
|
|
18
|
-
extensions. Hot paths are designed around bounded buffers, reusable immutable
|
|
19
|
-
configuration, and low-allocation command batches.
|
|
10
|
+
SolidJobs is **not compatible with Sidekiq**. It does not read Sidekiq queues,
|
|
11
|
+
does not write Sidekiq payloads, and does not expose Sidekiq's job API. Existing
|
|
12
|
+
applications and queued work must be migrated explicitly.
|
|
20
13
|
|
|
21
14
|
## Installation
|
|
22
15
|
|
|
23
|
-
Add SolidJobs 0.1 to your bundle:
|
|
24
|
-
|
|
25
16
|
```ruby
|
|
26
|
-
gem "solid-jobs"
|
|
17
|
+
gem "solid-jobs"
|
|
27
18
|
```
|
|
28
19
|
|
|
29
|
-
Then run
|
|
30
|
-
|
|
31
|
-
```sh
|
|
32
|
-
bundle install
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Delivery semantics
|
|
36
|
-
|
|
37
|
-
SolidJobs provides **at-least-once** job delivery. A worker atomically moves a
|
|
38
|
-
job from `queue:<name>` to a process reservation list before execution and
|
|
39
|
-
removes it only after a successful ACK. Graceful shutdown requeues unfinished
|
|
40
|
-
jobs; reservations owned by a crashed process are recovered into their
|
|
41
|
-
original queues.
|
|
20
|
+
Then run `bundle install`.
|
|
42
21
|
|
|
43
|
-
|
|
44
|
-
ACK. The recovered job will then run again. Jobs must therefore be idempotent
|
|
45
|
-
or implement an application-level deduplication key when duplicate side
|
|
46
|
-
effects are unsafe. SolidJobs does not claim exactly-once execution.
|
|
22
|
+
## Defining and submitting tasks
|
|
47
23
|
|
|
48
24
|
```ruby
|
|
49
|
-
class
|
|
50
|
-
include SolidJobs::
|
|
25
|
+
class RecalculateAccount
|
|
26
|
+
include SolidJobs::Task
|
|
51
27
|
|
|
52
|
-
|
|
28
|
+
task_options channel: "critical", max_failures: 10
|
|
53
29
|
|
|
54
|
-
def
|
|
30
|
+
def execute_task(account_id)
|
|
55
31
|
Account.find(account_id).recalculate!
|
|
56
32
|
end
|
|
57
33
|
end
|
|
58
34
|
|
|
59
|
-
|
|
60
|
-
|
|
35
|
+
RecalculateAccount.enqueue(42)
|
|
36
|
+
RecalculateAccount.enqueue_after(30, 42)
|
|
37
|
+
RecalculateAccount.schedule_at(Time.now + 300, 42)
|
|
38
|
+
RecalculateAccount.enqueue_many([[42], [43], [44]])
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The persisted envelope is specific to SolidJobs:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"id": "7ec33ed5-1b77-4bde-8960-bd77231f10ef",
|
|
46
|
+
"task": "RecalculateAccount",
|
|
47
|
+
"arguments": [42],
|
|
48
|
+
"channel": "critical",
|
|
49
|
+
"max_failures": 10,
|
|
50
|
+
"created_ms": 1790981000000,
|
|
51
|
+
"queued_ms": 1790981000001
|
|
52
|
+
}
|
|
61
53
|
```
|
|
62
54
|
|
|
63
|
-
|
|
55
|
+
All internal Redis keys use the `solid_jobs:` namespace. Ready work is stored
|
|
56
|
+
under `solid_jobs:channel:<name>`; planned, retrying, discarded, node, claim,
|
|
57
|
+
attempt, and metric data use separate namespaced keys.
|
|
58
|
+
|
|
59
|
+
Run executors:
|
|
64
60
|
|
|
65
61
|
```sh
|
|
66
62
|
bundle exec solid-jobs --require ./config/environment \
|
|
67
|
-
--concurrency 8 --
|
|
63
|
+
--concurrency 8 --channel critical,3 --channel default
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Configuration
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
SolidJobs.configure do |config|
|
|
70
|
+
config.channels = [["critical", 3], "default"]
|
|
71
|
+
config.channel_order = :weighted
|
|
72
|
+
config.concurrency = 8
|
|
73
|
+
config.shutdown_timeout = 25
|
|
74
|
+
config.default_task_options = {
|
|
75
|
+
channel: "default",
|
|
76
|
+
max_failures: 25,
|
|
77
|
+
}
|
|
78
|
+
end
|
|
68
79
|
```
|
|
69
80
|
|
|
70
|
-
|
|
81
|
+
`channel_order` accepts `:weighted` for bounded weighted round-robin,
|
|
82
|
+
`:priority` for declaration-order priority, and `:shuffle` for random
|
|
83
|
+
selection from the weighted channel list.
|
|
71
84
|
|
|
72
|
-
|
|
85
|
+
## Interceptors
|
|
73
86
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
bundle exec rake test
|
|
87
|
+
Publication and execution use SolidJobs interceptors. An interceptor implements
|
|
88
|
+
`around(context)` and yields to continue:
|
|
77
89
|
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
```ruby
|
|
91
|
+
class TraceExecution
|
|
92
|
+
def around(context)
|
|
93
|
+
Telemetry.start(context.envelope.fetch("id"))
|
|
94
|
+
yield
|
|
95
|
+
ensure
|
|
96
|
+
Telemetry.finish
|
|
97
|
+
end
|
|
98
|
+
end
|
|
80
99
|
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
SolidJobs.configure do |config|
|
|
101
|
+
config.execute_interceptors.use(TraceExecution)
|
|
102
|
+
end
|
|
103
|
+
```
|
|
83
104
|
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
Publication interceptors receive `SolidJobs::Publisher::Publication`; execution
|
|
106
|
+
interceptors receive `SolidJobs::Executor::Execution`.
|
|
86
107
|
|
|
87
|
-
|
|
88
|
-
STARTUP_TORTURE_CYCLES=1000 \
|
|
89
|
-
STARTUP_TORTURE_READERS=100 \
|
|
90
|
-
bundle exec rake startup_torture
|
|
108
|
+
## Failure handling
|
|
91
109
|
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
Tasks default to 25 failures. A task can customize the delay or final action:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
class ImportCatalog
|
|
114
|
+
include SolidJobs::Task
|
|
115
|
+
|
|
116
|
+
task_options max_failures: 8, retry_within: 3_600
|
|
117
|
+
|
|
118
|
+
retry_delay do |failure_count, error, envelope|
|
|
119
|
+
:drop if error.is_a?(InvalidCatalog)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
after_final_failure do |envelope, error|
|
|
123
|
+
Alerts.catalog_import_failed(envelope.fetch("id"), error)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
94
126
|
```
|
|
95
127
|
|
|
96
|
-
|
|
97
|
-
|
|
128
|
+
`retry_delay` may return a delay in seconds, `:drop`, or `:archive`. Without an
|
|
129
|
+
override, SolidJobs uses capped exponential backoff with equal jitter.
|
|
130
|
+
|
|
131
|
+
## Delivery semantics
|
|
98
132
|
|
|
99
|
-
|
|
133
|
+
SolidJobs provides **at-least-once** delivery. An executor atomically claims a
|
|
134
|
+
task before execution and completes the claim only after `execute_task` returns.
|
|
135
|
+
Graceful shutdown requeues unfinished tasks. Claims owned by a crashed node are
|
|
136
|
+
recovered into their original channels.
|
|
100
137
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
138
|
+
A process can still crash after an application side effect and before claim
|
|
139
|
+
completion. The recovered task then runs again. Tasks must be idempotent or use
|
|
140
|
+
application-level deduplication when duplicate effects are unsafe.
|
|
141
|
+
|
|
142
|
+
See [docs/reliability.md](docs/reliability.md) for the state machine, claim
|
|
143
|
+
fencing, recovery rules, and Ruby Ractor caveats.
|
|
144
|
+
|
|
145
|
+
## Node control
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
node = SolidJobs::Nodes.new.first
|
|
149
|
+
node.request_control(:pause)
|
|
150
|
+
node.request_control(:backtraces)
|
|
151
|
+
node.request_control(:shutdown)
|
|
105
152
|
```
|
|
106
153
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
and fenced ACK. Fetch decodes the payload once for both reservation metadata
|
|
110
|
-
and dispatch; its job body is intentionally empty.
|
|
154
|
+
Control requests are asynchronous and use the selected node's namespaced Redis
|
|
155
|
+
mailbox. Unknown actions raise `KeyError` without writing a request.
|
|
111
156
|
|
|
112
|
-
|
|
157
|
+
## Lab
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
SolidJobs.testing!(:capture) do
|
|
161
|
+
RecalculateAccount.enqueue(42)
|
|
162
|
+
RecalculateAccount.captured
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
SolidJobs.testing!(:execute) do
|
|
166
|
+
RecalculateAccount.enqueue(42)
|
|
167
|
+
end
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Run the project suites:
|
|
113
171
|
|
|
114
172
|
```sh
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
bundle exec rake
|
|
173
|
+
bundle exec rake test
|
|
174
|
+
STRESS_JOBS=10000 bundle exec rake stress
|
|
175
|
+
SOLID_JOBS_TORTURE=1 STRESS_JOBS=100000 bundle exec rake torture
|
|
176
|
+
SOLID_JOBS_SOAK=1 SOLID_JOBS_SOAK_SECONDS=86400 bundle exec rake soak
|
|
118
177
|
```
|
|
119
178
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
| Concurrency | Sidekiq jobs/s | SolidJobs jobs/s | SolidJobs scaling | Sidekiq CPU-s/1k | SolidJobs CPU-s/1k | Sidekiq RSS | SolidJobs RSS | Sidekiq alloc/job | SolidJobs alloc/job |
|
|
138
|
-
|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
139
|
-
| 1 | 289 | 281 | 100.0% | 3.35 | 3.40 | 41.4 MiB | 81.8 MiB | 117.2 | 84.0 |
|
|
140
|
-
| 2 | 296 | 549 | 97.7% | 3.38 | 3.44 | 41.7 MiB | 83.1 MiB | 116.8 | 79.7 |
|
|
141
|
-
| 4 | 298 | 1,090 | 97.0% | 3.37 | 3.43 | 41.8 MiB | 79.5 MiB | 111.1 | 77.7 |
|
|
142
|
-
| 8 | 298 | 2,053 | 91.4% | 3.36 | 3.67 | 42.4 MiB | 74.1 MiB | 108.1 | 74.3 |
|
|
143
|
-
|
|
144
|
-
At eight concurrency units, SolidJobs reaches 2,053 jobs/s versus 298 jobs/s
|
|
145
|
-
for Sidekiq. This is Ractor parallelism rather than equal CPU efficiency:
|
|
146
|
-
SolidJobs consumes 752.6% CPU and 3.67 CPU-seconds per 1,000 jobs, while
|
|
147
|
-
Sidekiq consumes 100.2% CPU and 3.36 CPU-seconds per 1,000 jobs. SolidJobs
|
|
148
|
-
also uses more RSS, but reaches 27.71 jobs/s/MiB versus 7.03 for Sidekiq.
|
|
149
|
-
|
|
150
|
-
These are local synthetic measurements, not application-capacity claims.
|
|
151
|
-
Queue p95/p99 values in this run use sparse sampling and are excluded from the
|
|
152
|
-
summary until the final latency campaign increases the sample count. Ruby
|
|
153
|
-
3.4.4 eight-Ractor results are also excluded: Ruby 3.4's Ractor scheduler
|
|
154
|
-
crashed (concurrent TCP/RESP initialization, reproduced on macOS arm64 and
|
|
155
|
-
Linux x86_64) or deadlocked VM-wide on a GC barrier under cross-Ractor
|
|
156
|
-
message traffic (`test/support/ractor_barrier_repro.rb` reproduces it without
|
|
157
|
-
SolidJobs).
|
|
158
|
-
Ruby 4.0.1 passed the equivalent reproducers, and `StartupBarrier` serializes
|
|
159
|
-
component initialization before releasing normal parallel processing.
|
|
160
|
-
**Multi-Ractor servers are recommended on Ruby ≥ 4.0**; see
|
|
161
|
-
`docs/reliability.md`.
|
|
162
|
-
|
|
163
|
-
The project is under active development. The Web UI and commercial Sidekiq
|
|
164
|
-
features are not part of the initial scope.
|
|
179
|
+
## Migrating from Sidekiq
|
|
180
|
+
|
|
181
|
+
There is no transparent migration path because compatibility is intentionally
|
|
182
|
+
absent:
|
|
183
|
+
|
|
184
|
+
1. Replace `include Sidekiq::Job` with `include SolidJobs::Task`.
|
|
185
|
+
2. Replace `sidekiq_options` with `task_options`.
|
|
186
|
+
3. Replace `perform_async`, `perform_in`, and `perform_bulk` with `enqueue`,
|
|
187
|
+
`enqueue_after`, and `enqueue_many`.
|
|
188
|
+
4. Replace middleware with SolidJobs interceptors.
|
|
189
|
+
5. Drain or export existing Sidekiq queues before switching. SolidJobs will not
|
|
190
|
+
consume them.
|
|
191
|
+
6. Start SolidJobs with `--channel`; `--queue` is not accepted.
|
|
192
|
+
|
|
193
|
+
The Active Job adapter remains available as
|
|
194
|
+
`ActiveJob::QueueAdapters::SolidJobsAdapter`, but it writes only SolidJobs
|
|
195
|
+
envelopes and keys.
|