solid-jobs 0.1.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 +7 -0
- data/CHANGELOG.md +27 -0
- data/LICENSE.txt +22 -0
- data/README.md +159 -0
- data/docs/reliability.md +114 -0
- data/exe/solid-jobs +8 -0
- data/lib/active_job/queue_adapters/solid_jobs_adapter.rb +42 -0
- data/lib/solid_jobs/active_job.rb +16 -0
- data/lib/solid_jobs/api.rb +457 -0
- data/lib/solid_jobs/cli.rb +135 -0
- data/lib/solid_jobs/client.rb +202 -0
- data/lib/solid_jobs/config.rb +171 -0
- data/lib/solid_jobs/errors.rb +9 -0
- data/lib/solid_jobs/fetch.rb +310 -0
- data/lib/solid_jobs/heartbeat.rb +60 -0
- data/lib/solid_jobs/integrity_check.rb +222 -0
- data/lib/solid_jobs/job.rb +156 -0
- data/lib/solid_jobs/middleware/chain.rb +104 -0
- data/lib/solid_jobs/processor.rb +152 -0
- data/lib/solid_jobs/ractor_support.rb +11 -0
- data/lib/solid_jobs/rails.rb +16 -0
- data/lib/solid_jobs/recovery.rb +65 -0
- data/lib/solid_jobs/retry_service.rb +100 -0
- data/lib/solid_jobs/scheduler.rb +64 -0
- data/lib/solid_jobs/server.rb +221 -0
- data/lib/solid_jobs/startup_barrier.rb +126 -0
- data/lib/solid_jobs/testing.rb +69 -0
- data/lib/solid_jobs/utilities.rb +52 -0
- data/lib/solid_jobs/version.rb +6 -0
- data/lib/solid_jobs/worker.rb +35 -0
- data/lib/solid_jobs.rb +92 -0
- metadata +189 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8bbfb02b4261c0c6164bae65b6a47ebceda70a1dd0b3b59835e1a48a9c58bc97
|
|
4
|
+
data.tar.gz: f4306875809f7d8c5287ba9de5022ee1ac29da163a3448f0ed7de0492c9beccd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 71c1383a610c4d230f7db3b02f09664de638ff5009b22f3b44fe3b7dedbfe0f2e0aad5fb791c6816adea711b0e3e20766dc406b40e21cfe109ae429e8d07d7fd
|
|
7
|
+
data.tar.gz: d5e9beff88328ba42cc3a2bdf3167fd12acd7391b8c61e373664bc408b4055bcdb9fdb0915308b0fde7c521aea7527be63ba8e18d332458938a95a9401897832
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-09-30
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Ractor-oriented client, Processor, Scheduler, Heartbeat, and Server runtime.
|
|
12
|
+
- Sidekiq-compatible Redis queue keys and open-source job payload format.
|
|
13
|
+
- Immediate, scheduled, retry, and dead-job handling.
|
|
14
|
+
- At-least-once reservations with atomic journaling, generation-fenced ACK
|
|
15
|
+
and requeue operations, and crashed-process recovery.
|
|
16
|
+
- `SolidJobs::IntegrityCheck` for lost jobs, orphaned references, invalid
|
|
17
|
+
reservations, dangling indexes, and impossible duplicate states.
|
|
18
|
+
- `SolidJobs::StartupBarrier`, which preconnects every component before
|
|
19
|
+
releasing Processors into their fetch loops.
|
|
20
|
+
- Graceful quiet and shutdown handling with requeue of interrupted work.
|
|
21
|
+
- Minitest unit, Redis integration, bounded stress, torture, startup-torture,
|
|
22
|
+
and soak suites.
|
|
23
|
+
- Reliable-hot-path and CPU-scaling profilers plus the independent Sidekiq
|
|
24
|
+
comparison benchmark.
|
|
25
|
+
|
|
26
|
+
[Unreleased]: https://github.com/nicolasva/solid-jobs/compare/v0.1.0...HEAD
|
|
27
|
+
[0.1.0]: https://github.com/nicolasva/solid-jobs/releases/tag/v0.1.0
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nicolas Vandenbogaerde
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# SolidJobs
|
|
2
|
+
|
|
3
|
+
[](https://github.com/nicolasva/solid-jobs/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codeclimate.com/github/nicolasva/solid-jobs)
|
|
5
|
+
[](https://rubygems.org/gems/solid-jobs)
|
|
6
|
+
[](https://www.rubydoc.info/gems/solid-jobs)
|
|
7
|
+
[](https://rubygems.org/gems/solid-jobs)
|
|
8
|
+
|
|
9
|
+
SolidJobs is a Ractor-oriented Redis background job system for Ruby. It uses
|
|
10
|
+
`solid-redis` for Redis access and keeps mutable clients, pools, middleware,
|
|
11
|
+
and runtime state local to their owning Ractor.
|
|
12
|
+
|
|
13
|
+
SolidJobs is an independent implementation. It does not depend on or load the
|
|
14
|
+
Sidekiq gem. Its Redis job payloads and queue keys are designed to be
|
|
15
|
+
compatible with the Sidekiq 8 open-source data format.
|
|
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.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Add SolidJobs 0.1 to your bundle:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
gem "solid-jobs", "~> 0.1.0"
|
|
27
|
+
```
|
|
28
|
+
|
|
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.
|
|
42
|
+
|
|
43
|
+
A process can still crash after the application side effect and before the
|
|
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.
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
class HardJob
|
|
50
|
+
include SolidJobs::Job
|
|
51
|
+
|
|
52
|
+
solid_jobs_options queue: "critical", retry: 10
|
|
53
|
+
|
|
54
|
+
def perform(account_id)
|
|
55
|
+
Account.find(account_id).recalculate!
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
HardJob.perform_async(42)
|
|
60
|
+
HardJob.perform_in(30, 42)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Run workers:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
bundle exec solid-jobs --require ./config/environment \
|
|
67
|
+
--concurrency 8 --queue critical,3 --queue default
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Tests
|
|
71
|
+
|
|
72
|
+
SolidJobs uses Minitest exclusively:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
# Unit and bounded Redis integration tests
|
|
76
|
+
bundle exec rake test
|
|
77
|
+
|
|
78
|
+
# Bounded concurrency and multi-process recovery stress
|
|
79
|
+
STRESS_JOBS=10000 bundle exec rake stress
|
|
80
|
+
|
|
81
|
+
# Reproducible random-fault campaign
|
|
82
|
+
SOLID_JOBS_TORTURE=1 STRESS_JOBS=100000 bundle exec rake torture
|
|
83
|
+
|
|
84
|
+
# Re-run an exact failure sequence
|
|
85
|
+
SOLID_JOBS_TORTURE=1 STRESS_JOBS=100000 STRESS_SEED=123456 bundle exec rake torture
|
|
86
|
+
|
|
87
|
+
# Repeated fresh-process RESP/Ractor startup torture
|
|
88
|
+
STARTUP_TORTURE_CYCLES=1000 \
|
|
89
|
+
STARTUP_TORTURE_READERS=100 \
|
|
90
|
+
bundle exec rake startup_torture
|
|
91
|
+
|
|
92
|
+
# Long-running stability; defaults to 24 hours
|
|
93
|
+
SOLID_JOBS_SOAK=1 SOLID_JOBS_SOAK_SECONDS=86400 bundle exec rake soak
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The torture report reconciles enqueued, uniquely completed, duplicate,
|
|
97
|
+
dead, queued, and reserved jobs. Any non-zero `LOST` value fails the test.
|
|
98
|
+
|
|
99
|
+
Profile the reliable execution path independently from application work:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
REDIS_URL=redis://127.0.0.1:6379/0 \
|
|
103
|
+
HOT_PATH_JOBS=10000 \
|
|
104
|
+
bundle exec rake benchmark:hot_path
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The report separates time and allocations for reservation, payload reuse,
|
|
108
|
+
observability registration, dispatch/perform wrapping, observability cleanup,
|
|
109
|
+
and fenced ACK. Fetch decodes the payload once for both reservation metadata
|
|
110
|
+
and dispatch; its job body is intentionally empty.
|
|
111
|
+
|
|
112
|
+
Diagnose CPU scaling independently from Redis:
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
CPU_SCALING_JOBS=1000 \
|
|
116
|
+
CPU_SCALING_ITERATIONS=210000 \
|
|
117
|
+
bundle exec rake benchmark:cpu_scaling
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
This runs the identical CPU loop through pure Ractors and through the
|
|
121
|
+
SolidJobs in-memory dispatch path. Each 1/2/4/8 case uses fresh processes and
|
|
122
|
+
reports execution latency, scaling efficiency, CPU-seconds per 1,000 jobs,
|
|
123
|
+
RSS, allocations, GC time, heap slots, and malloc growth.
|
|
124
|
+
|
|
125
|
+
## Sidekiq comparison
|
|
126
|
+
|
|
127
|
+
The separate `benchmark_sidekiq_solid-jobs` bundle runs Sidekiq and SolidJobs
|
|
128
|
+
against the same isolated Redis server. It covers enqueue, bulk enqueue,
|
|
129
|
+
CPU-bound processing, I/O-bound processing, mixed processing, and long-running
|
|
130
|
+
stability. Every measurement runs in a fresh Ruby process; client order
|
|
131
|
+
alternates and the default report uses the median of six repetitions.
|
|
132
|
+
|
|
133
|
+
The current homogeneous CPU-processing reference uses Ruby 4.0.1,
|
|
134
|
+
Sidekiq 8.1.7, a 210,000-iteration integer workload, and 1,000 jobs per case:
|
|
135
|
+
|
|
136
|
+
| 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 |
|
|
137
|
+
|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
138
|
+
| 1 | 142 | 138 | 100.0% | 6.95 | 7.11 | 41.5 MiB | 72.0 MiB | 129.8 | 89.9 |
|
|
139
|
+
| 2 | 144 | 272 | 98.7% | 6.94 | 7.16 | 41.8 MiB | 77.6 MiB | 117.5 | 81.3 |
|
|
140
|
+
| 4 | 143 | 539 | 97.8% | 6.99 | 7.18 | 41.9 MiB | 71.4 MiB | 111.9 | 77.2 |
|
|
141
|
+
| 8 | 144 | 957 | 86.7% | 6.94 | 8.01 | 42.2 MiB | 69.5 MiB | 108.7 | 75.4 |
|
|
142
|
+
|
|
143
|
+
At eight concurrency units, SolidJobs reaches 957 jobs/s versus 144 jobs/s
|
|
144
|
+
for one Sidekiq process. This is Ractor parallelism rather than equal CPU
|
|
145
|
+
efficiency: SolidJobs consumes 766% CPU and 8.01 CPU-seconds per 1,000 jobs,
|
|
146
|
+
while Sidekiq consumes 100% CPU and 6.94 CPU-seconds per 1,000 jobs. SolidJobs
|
|
147
|
+
also uses more RSS, but reaches 13.77 jobs/s/MiB versus 3.41 for Sidekiq.
|
|
148
|
+
|
|
149
|
+
These are local synthetic measurements, not application-capacity claims.
|
|
150
|
+
Queue p95/p99 values in this run use sparse sampling and are excluded from the
|
|
151
|
+
summary until the final latency campaign increases the sample count. Ruby
|
|
152
|
+
3.4.4 eight-Ractor results are also excluded: concurrent TCP/RESP
|
|
153
|
+
initialization triggered a reproducible native crash on the tested Apple
|
|
154
|
+
Silicon environment. Ruby 4.0.1 passed the equivalent reproducer 100/100
|
|
155
|
+
times, and `StartupBarrier` serializes component initialization before
|
|
156
|
+
releasing normal parallel processing.
|
|
157
|
+
|
|
158
|
+
The project is under active development. The Web UI and commercial Sidekiq
|
|
159
|
+
features are not part of the initial scope.
|
data/docs/reliability.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Reliability model
|
|
2
|
+
|
|
3
|
+
SolidJobs uses a Redis-backed at-least-once state machine:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
READY
|
|
7
|
+
|
|
|
8
|
+
| BLMOVE reservation
|
|
9
|
+
v
|
|
10
|
+
IN_PROGRESS ---- ACK/LREM ----> removed
|
|
11
|
+
|
|
|
12
|
+
+---- application error ----> RETRY or DEAD, then ACK
|
|
13
|
+
+---- graceful timeout -----> READY
|
|
14
|
+
+---- process crash --------> reservation retained
|
|
15
|
+
|
|
|
16
|
+
+---- recovery ----> READY
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The reservation list is named `<process-identity>:reserved:<processor-id>`.
|
|
20
|
+
Each execution receives a distinct reservation journal entry:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
job_id stable across replay
|
|
24
|
+
reservation_id unique per execution attempt
|
|
25
|
+
process_id owning process identity
|
|
26
|
+
worker_id owning Processor Ractor
|
|
27
|
+
attempt monotonically increasing execution count
|
|
28
|
+
reserved_at wall-clock reservation time
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
ACK and requeue are fenced by `reservation_id`. Their Lua scripts first
|
|
32
|
+
verify that the worker still owns the current journal generation. A delayed
|
|
33
|
+
or revived worker cannot remove or requeue a newer reservation, even when a
|
|
34
|
+
supervisor reuses the same processor slot.
|
|
35
|
+
|
|
36
|
+
The payload retains its canonical `queue` field, allowing another process to
|
|
37
|
+
restore it after the owner is no longer alive. Recovery uses process liveness
|
|
38
|
+
and heartbeat, never reservation age alone, so a legitimate long-running job
|
|
39
|
+
is not stolen while its owner remains alive.
|
|
40
|
+
|
|
41
|
+
## Failure boundaries
|
|
42
|
+
|
|
43
|
+
- Before reservation: the job remains in `queue:<name>`.
|
|
44
|
+
- After reservation or during `perform`: the job remains reserved.
|
|
45
|
+
- After the application effect but before ACK: recovery replays the job.
|
|
46
|
+
- Redis unavailable during ACK: the job remains reserved and is replayed.
|
|
47
|
+
- Graceful shutdown: the active job may finish within the configured timeout;
|
|
48
|
+
otherwise it is interrupted and requeued.
|
|
49
|
+
- `SIGKILL`: no handler runs; recovery relies exclusively on Redis state.
|
|
50
|
+
|
|
51
|
+
This design intentionally favors no job loss over duplicate suppression.
|
|
52
|
+
Exactly-once side effects require application-level idempotency.
|
|
53
|
+
|
|
54
|
+
## Startup isolation
|
|
55
|
+
|
|
56
|
+
The server does not reserve work while components are booting. Heartbeat,
|
|
57
|
+
Processor, and Scheduler Ractors initialize their local configuration and
|
|
58
|
+
Redis pool, report `READY` exactly once, and wait behind
|
|
59
|
+
`SolidJobs::StartupBarrier`. Processing starts only after every component is
|
|
60
|
+
ready:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
BOOTING -> ALL_READY -> RUNNING
|
|
64
|
+
\-------> BOOT_FAILED -> cleanup
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Boot failure is terminal. Already-ready components receive `:abort`, close
|
|
68
|
+
their local resources, and never enter their fetch loops. Cleanup is
|
|
69
|
+
idempotent. Component startup is serialized, avoiding concurrent TCP/RESP
|
|
70
|
+
initialization paths known to crash Ruby 3.4.4 on the tested Apple Silicon
|
|
71
|
+
environment; normal processing remains parallel after `RUNNING`.
|
|
72
|
+
|
|
73
|
+
## Integrity auditing
|
|
74
|
+
|
|
75
|
+
Fault and chaos tests can reconcile a known set of job IDs against every
|
|
76
|
+
Redis-backed state:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
report = SolidJobs::IntegrityCheck.call(
|
|
80
|
+
expected_job_ids: submitted_job_ids,
|
|
81
|
+
acked_key: "test:completed",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
raise report.inspect unless report.ok?
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The report separates lost jobs, unexpected/orphaned jobs, inconsistent
|
|
88
|
+
reservation journals, dangling attempt indexes, duplicate active states, and
|
|
89
|
+
malformed payloads. ACK removes the completed job's attempt index atomically;
|
|
90
|
+
requeue retains it so a recovered reservation increments the same attempt
|
|
91
|
+
sequence.
|
|
92
|
+
|
|
93
|
+
## Backpressure and queues
|
|
94
|
+
|
|
95
|
+
Each Processor owns at most one reservation and reserves only immediately
|
|
96
|
+
before execution. A process with concurrency `N` therefore holds at most `N`
|
|
97
|
+
active reservations, regardless of Redis queue depth.
|
|
98
|
+
|
|
99
|
+
Queue mode defaults to `:weighted`:
|
|
100
|
+
|
|
101
|
+
- `:weighted` uses bounded weighted round-robin and does not starve configured
|
|
102
|
+
queues;
|
|
103
|
+
- `:strict` always checks queues in declaration order and may intentionally
|
|
104
|
+
starve lower-priority queues while a higher-priority queue remains busy;
|
|
105
|
+
- `:random` samples the configured weighted queue list on each reservation.
|
|
106
|
+
|
|
107
|
+
Paused queues are excluded before reservation.
|
|
108
|
+
|
|
109
|
+
## Retry storms
|
|
110
|
+
|
|
111
|
+
Retries use capped exponential backoff with equal jitter. For attempt `n`, the
|
|
112
|
+
ceiling is `min(retry_base_delay * 2**n, retry_max_delay)` and the actual delay
|
|
113
|
+
is distributed between half and all of that ceiling. Defaults are 15 seconds
|
|
114
|
+
and one hour. This spreads recovery traffic after a shared external outage.
|
data/exe/solid-jobs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "solid_jobs"
|
|
4
|
+
require "solid_jobs/active_job"
|
|
5
|
+
|
|
6
|
+
module ActiveJob
|
|
7
|
+
module QueueAdapters
|
|
8
|
+
class SolidJobsAdapter
|
|
9
|
+
def enqueue(job)
|
|
10
|
+
job.provider_job_id = push(job)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def enqueue_at(job, timestamp)
|
|
14
|
+
job.provider_job_id = push(job, at: timestamp)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def enqueue_all(jobs)
|
|
18
|
+
jobs.count do |job|
|
|
19
|
+
job.provider_job_id = job.scheduled_at ? enqueue_at(job, job.scheduled_at.to_f) : enqueue(job)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stopping?
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def push(job, at: nil)
|
|
30
|
+
payload = {
|
|
31
|
+
"class" => SolidJobs::ActiveJob::Wrapper,
|
|
32
|
+
"wrapped" => job.class.name,
|
|
33
|
+
"queue" => job.queue_name,
|
|
34
|
+
"args" => [job.serialize],
|
|
35
|
+
}
|
|
36
|
+
payload["at"] = at if at
|
|
37
|
+
SolidJobs::Client.push(payload)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SolidJobs
|
|
4
|
+
module ActiveJob
|
|
5
|
+
class Wrapper
|
|
6
|
+
include SolidJobs::Job
|
|
7
|
+
solid_jobs_options retry: true
|
|
8
|
+
|
|
9
|
+
def perform(job_data)
|
|
10
|
+
::ActiveJob::Base.execute(job_data.merge("provider_job_id" => jid))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
JobWrapper = Wrapper
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|