workhorse 1.4.2 → 1.4.5
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 +23 -1
- data/README.md +11 -0
- data/RUBY_VERSION +1 -1
- data/VERSION +1 -1
- data/lib/workhorse/daemon/shell_handler.rb +4 -1
- data/lib/workhorse/daemon.rb +23 -2
- data/lib/workhorse/poller.rb +8 -0
- data/lib/workhorse/worker.rb +6 -3
- data/lib/workhorse.rb +10 -0
- data/test/workhorse/yjit_test.rb +37 -0
- data/workhorse.gemspec +9 -9
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef9cd623d06cab42a5c5a849f9a5c334c0bb8f4dd517f2c84e5ba3c4df611b24
|
|
4
|
+
data.tar.gz: 9681900417bc660a347afeeaebf6cf57fa342268afc38c24b4e5ce11479ce1e3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 86a5b9f9db82efbd890dc77fa763dcc1052027df45d922358428e721bfe3e900670e28b1e55af06e04972fef7c6408fe8a445239443f0707063281d4baf344fe
|
|
7
|
+
data.tar.gz: 74f47b979b3589b5530947638c7ec7a6acbb9f85599c88bd9eccaf25fcecf5a92addecb58fa9357bc07eb840bf16b31e5a7fe7fe2f9a6e11fa697b31d9aaf526
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Workhorse Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.5 - 2026-05-09
|
|
4
|
+
|
|
5
|
+
* Close the lockfile after releasing the lock in the ShellHandler.
|
|
6
|
+
|
|
7
|
+
Sitrox reference: #120574.
|
|
8
|
+
|
|
9
|
+
* Prevent YJIT from being enabled when `RUBY_YJIT_ENABLE=0` is set. This allows
|
|
10
|
+
running workhorse commands in systemd services that set
|
|
11
|
+
`MemoryDenyWriteExecute=yes`.
|
|
12
|
+
|
|
13
|
+
Sitrox reference: #120574.
|
|
14
|
+
|
|
15
|
+
## 1.4.4 - 2026-04-28
|
|
16
|
+
|
|
17
|
+
* Make debug logging (enabled if `config.debug_log_path` is set) more verbose.
|
|
18
|
+
|
|
19
|
+
Sitrox reference: #120574.
|
|
20
|
+
|
|
21
|
+
## 1.4.3 - 2026-04-28
|
|
22
|
+
|
|
23
|
+
* Yanked from RubyGems. Do not use this release.
|
|
24
|
+
|
|
3
25
|
## 1.4.2 - 2026-02-20
|
|
4
26
|
|
|
5
27
|
* Detach forked worker processes into their own session using `Process.setsid`.
|
|
@@ -62,7 +84,7 @@
|
|
|
62
84
|
|
|
63
85
|
## 1.3.0.rc4 - 2025-08-27
|
|
64
86
|
|
|
65
|
-
* Fix race-condition in polling mechanism which could result in workers
|
|
87
|
+
* Fix race-condition in polling mechanism which could result in workers
|
|
66
88
|
trying to run a job that is not yet locked.
|
|
67
89
|
|
|
68
90
|
Sitrox reference: #128333.
|
data/README.md
CHANGED
|
@@ -529,6 +529,17 @@ ActiveSupport.on_load :workhorse_db_job do
|
|
|
529
529
|
end
|
|
530
530
|
```
|
|
531
531
|
|
|
532
|
+
## Running in systemd services
|
|
533
|
+
|
|
534
|
+
When running workhorse commands inside a systemd service that sets
|
|
535
|
+
`MemoryDenyWriteExecute=yes`, Ruby's YJIT cannot allocate executable memory and
|
|
536
|
+
will crash. To prevent this, set `RUBY_YJIT_ENABLE=0` before invoking the
|
|
537
|
+
workhorse command:
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
RUBY_YJIT_ENABLE=0 ./bin/workhorse restart-logging
|
|
541
|
+
```
|
|
542
|
+
|
|
532
543
|
## Debug logging
|
|
533
544
|
|
|
534
545
|
Workhorse includes an optional debug log for diagnosing issues with signal
|
data/RUBY_VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ruby-3.
|
|
1
|
+
ruby-3.3.5
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.4.
|
|
1
|
+
1.4.5
|
|
@@ -81,13 +81,16 @@ module Workhorse
|
|
|
81
81
|
status = 99
|
|
82
82
|
end
|
|
83
83
|
rescue StandardError => e
|
|
84
|
+
Workhorse.debug_log("ShellHandler: #{ARGV.first} failed with #{e.class}: #{e.message}")
|
|
84
85
|
warn "#{e.message}\n#{e.backtrace.join("\n")}"
|
|
85
86
|
status = 99
|
|
86
87
|
ensure
|
|
87
88
|
if lockfile
|
|
88
89
|
Workhorse.debug_log("ShellHandler: releasing lock for #{ARGV.first}")
|
|
89
90
|
lockfile.flock(File::LOCK_UN)
|
|
91
|
+
lockfile.close
|
|
90
92
|
end
|
|
93
|
+
Workhorse.debug_log("ShellHandler: exiting with status #{status}")
|
|
91
94
|
exit! status
|
|
92
95
|
end
|
|
93
96
|
end
|
|
@@ -143,7 +146,7 @@ module Workhorse
|
|
|
143
146
|
|
|
144
147
|
def self.acquire_lock(lockfile_path, flags)
|
|
145
148
|
if Workhorse.lock_shell_commands
|
|
146
|
-
lockfile = File.open(lockfile_path, 'a')
|
|
149
|
+
lockfile = File.open(lockfile_path, 'a') # rubocop:disable Style/FileOpen
|
|
147
150
|
result = lockfile.flock(flags)
|
|
148
151
|
|
|
149
152
|
if result == false
|
data/lib/workhorse/daemon.rb
CHANGED
|
@@ -82,6 +82,8 @@ module Workhorse
|
|
|
82
82
|
def start(quiet: false)
|
|
83
83
|
code = 0
|
|
84
84
|
|
|
85
|
+
Workhorse.debug_log("Daemon: starting #{@workers.count} worker(s)")
|
|
86
|
+
|
|
85
87
|
# Holds messages in format [[<message>, <severity>]]
|
|
86
88
|
messages = []
|
|
87
89
|
|
|
@@ -89,9 +91,11 @@ module Workhorse
|
|
|
89
91
|
pid_file, pid, active = read_pid(worker)
|
|
90
92
|
|
|
91
93
|
if pid_file && pid && active
|
|
94
|
+
Workhorse.debug_log("Daemon start: worker ##{worker.id} (#{worker.name}) already running (PID #{pid})")
|
|
92
95
|
messages << ["Worker ##{worker.id} (#{worker.name}): Already started (PID #{pid})", 2] unless quiet
|
|
93
96
|
code = 2
|
|
94
97
|
elsif pid_file
|
|
98
|
+
Workhorse.debug_log("Daemon start: worker ##{worker.id} (#{worker.name}) has stale pid file (PID #{pid.inspect}), starting")
|
|
95
99
|
File.delete pid_file
|
|
96
100
|
|
|
97
101
|
shutdown_file = pid ? Workhorse::Worker.shutdown_file_for(pid) : nil
|
|
@@ -101,6 +105,7 @@ module Workhorse
|
|
|
101
105
|
start_worker worker
|
|
102
106
|
FileUtils.rm(shutdown_file) if shutdown_file
|
|
103
107
|
else
|
|
108
|
+
Workhorse.debug_log("Daemon start: worker ##{worker.id} (#{worker.name}) not running, starting")
|
|
104
109
|
messages << ["Worker ##{worker.id} (#{worker.name}): Starting", 1] unless quiet
|
|
105
110
|
start_worker worker
|
|
106
111
|
end
|
|
@@ -115,6 +120,7 @@ module Workhorse
|
|
|
115
120
|
end
|
|
116
121
|
end
|
|
117
122
|
|
|
123
|
+
Workhorse.debug_log("Daemon: start complete, exit code=#{code}")
|
|
118
124
|
return code
|
|
119
125
|
end
|
|
120
126
|
|
|
@@ -126,21 +132,27 @@ module Workhorse
|
|
|
126
132
|
def stop(kill = false, quiet: false)
|
|
127
133
|
code = 0
|
|
128
134
|
|
|
135
|
+
Workhorse.debug_log("Daemon: stopping #{@workers.count} worker(s) (kill=#{kill})")
|
|
136
|
+
|
|
129
137
|
for_each_worker do |worker|
|
|
130
138
|
pid_file, pid, active = read_pid(worker)
|
|
131
139
|
|
|
132
140
|
if pid_file && pid && active
|
|
141
|
+
Workhorse.debug_log("Daemon stop: worker ##{worker.id} (#{worker.name}) running (PID #{pid}), stopping")
|
|
133
142
|
puts "Worker (#{worker.name}) ##{worker.id}: Stopping" unless quiet
|
|
134
143
|
stop_worker pid_file, pid, kill: kill
|
|
135
144
|
elsif pid_file
|
|
145
|
+
Workhorse.debug_log("Daemon stop: worker ##{worker.id} (#{worker.name}) stale pid file (PID #{pid.inspect})")
|
|
136
146
|
File.delete pid_file
|
|
137
147
|
puts "Worker (#{worker.name}) ##{worker.id}: Already stopped (stale PID file)" unless quiet
|
|
138
148
|
else
|
|
149
|
+
Workhorse.debug_log("Daemon stop: worker ##{worker.id} (#{worker.name}) already stopped")
|
|
139
150
|
warn "Worker (#{worker.name}) ##{worker.id}: Already stopped" unless quiet
|
|
140
151
|
code = 2
|
|
141
152
|
end
|
|
142
153
|
end
|
|
143
154
|
|
|
155
|
+
Workhorse.debug_log("Daemon: stop complete, exit code=#{code}")
|
|
144
156
|
return code
|
|
145
157
|
end
|
|
146
158
|
|
|
@@ -155,16 +167,20 @@ module Workhorse
|
|
|
155
167
|
pid_file, pid, active = read_pid(worker)
|
|
156
168
|
|
|
157
169
|
if pid_file && pid && active
|
|
170
|
+
Workhorse.debug_log("Daemon status: worker ##{worker.id} (#{worker.name}) running (PID #{pid})")
|
|
158
171
|
puts "Worker ##{worker.id} (#{worker.name}): Running" unless quiet
|
|
159
172
|
elsif pid_file
|
|
173
|
+
Workhorse.debug_log("Daemon status: worker ##{worker.id} (#{worker.name}) not running (stale PID file, PID #{pid.inspect})")
|
|
160
174
|
warn "Worker ##{worker.id} (#{worker.name}): Not running (stale PID file)" unless quiet
|
|
161
175
|
code = 2
|
|
162
176
|
else
|
|
177
|
+
Workhorse.debug_log("Daemon status: worker ##{worker.id} (#{worker.name}) not running (no pid file)")
|
|
163
178
|
warn "Worker ##{worker.id} (#{worker.name}): Not running" unless quiet
|
|
164
179
|
code = 2
|
|
165
180
|
end
|
|
166
181
|
end
|
|
167
182
|
|
|
183
|
+
Workhorse.debug_log("Daemon: status complete, exit code=#{code}")
|
|
168
184
|
return code
|
|
169
185
|
end
|
|
170
186
|
|
|
@@ -179,9 +195,14 @@ module Workhorse
|
|
|
179
195
|
should_be_running = true
|
|
180
196
|
end
|
|
181
197
|
|
|
182
|
-
|
|
198
|
+
status_code = status(quiet: true)
|
|
199
|
+
Workhorse.debug_log("Daemon watch: should_be_running=#{should_be_running}, status_code=#{status_code}")
|
|
200
|
+
|
|
201
|
+
if should_be_running && status_code != 0
|
|
202
|
+
Workhorse.debug_log('Daemon watch: starting workers')
|
|
183
203
|
return start(quiet: Workhorse.silence_watcher)
|
|
184
204
|
else
|
|
205
|
+
Workhorse.debug_log('Daemon watch: no action needed')
|
|
185
206
|
return 0
|
|
186
207
|
end
|
|
187
208
|
end
|
|
@@ -289,7 +310,7 @@ module Workhorse
|
|
|
289
310
|
@lockfile&.close
|
|
290
311
|
# Reopen pipes to prevent #107576
|
|
291
312
|
$stdin.reopen File.open(File::NULL, 'r')
|
|
292
|
-
null_out = File.open
|
|
313
|
+
null_out = File.open(File::NULL, 'w') # rubocop:disable Style/FileOpen
|
|
293
314
|
$stdout.reopen null_out
|
|
294
315
|
$stderr.reopen null_out
|
|
295
316
|
|
data/lib/workhorse/poller.rb
CHANGED
|
@@ -49,14 +49,18 @@ module Workhorse
|
|
|
49
49
|
fail 'Poller is already running.' if running?
|
|
50
50
|
@running = true
|
|
51
51
|
|
|
52
|
+
Workhorse.debug_log("[Job worker #{worker.id}] Poller starting")
|
|
53
|
+
|
|
52
54
|
clean_stuck_jobs! if Workhorse.clean_stuck_jobs
|
|
53
55
|
|
|
54
56
|
@thread = Thread.new do
|
|
57
|
+
Workhorse.debug_log("[Job worker #{worker.id}] Poller thread started")
|
|
55
58
|
loop do
|
|
56
59
|
break unless running?
|
|
57
60
|
|
|
58
61
|
begin
|
|
59
62
|
unless @before_poll.call
|
|
63
|
+
Workhorse.debug_log("[Job worker #{worker.id}] before_poll returned false, triggering worker shutdown")
|
|
60
64
|
Thread.new { worker.shutdown }
|
|
61
65
|
sleep
|
|
62
66
|
next
|
|
@@ -65,6 +69,7 @@ module Workhorse
|
|
|
65
69
|
poll
|
|
66
70
|
sleep
|
|
67
71
|
rescue Exception => e
|
|
72
|
+
Workhorse.debug_log("[Job worker #{worker.id}] Poller exception, shutting down: #{e.class}: #{e.message}")
|
|
68
73
|
worker.log %(Poll encountered exception:\n#{e.message}\n#{e.backtrace.join("\n")})
|
|
69
74
|
worker.log 'Worker shutting down...'
|
|
70
75
|
Workhorse.on_exception.call(e) unless Workhorse.silence_poller_exceptions
|
|
@@ -73,6 +78,7 @@ module Workhorse
|
|
|
73
78
|
break
|
|
74
79
|
end
|
|
75
80
|
end
|
|
81
|
+
Workhorse.debug_log("[Job worker #{worker.id}] Poller thread exiting")
|
|
76
82
|
end
|
|
77
83
|
end
|
|
78
84
|
|
|
@@ -82,8 +88,10 @@ module Workhorse
|
|
|
82
88
|
# @raise [RuntimeError] If poller is not running
|
|
83
89
|
def shutdown
|
|
84
90
|
fail 'Poller is not running.' unless running?
|
|
91
|
+
Workhorse.debug_log("[Job worker #{worker.id}] Poller shutting down")
|
|
85
92
|
@running = false
|
|
86
93
|
wait
|
|
94
|
+
Workhorse.debug_log("[Job worker #{worker.id}] Poller shut down")
|
|
87
95
|
end
|
|
88
96
|
|
|
89
97
|
# Waits for the poller thread to complete.
|
data/lib/workhorse/worker.rb
CHANGED
|
@@ -302,18 +302,19 @@ module Workhorse
|
|
|
302
302
|
def trap_log_reopen
|
|
303
303
|
Signal.trap(LOG_REOPEN_SIGNAL) do
|
|
304
304
|
Thread.new do
|
|
305
|
-
Workhorse.debug_log("[Job worker #{id}]
|
|
305
|
+
Workhorse.debug_log("[Job worker #{id}] #{LOG_REOPEN_SIGNAL} received, logger state before reopen: #{describe_logger(logger)}")
|
|
306
306
|
|
|
307
307
|
logger&.reopen
|
|
308
308
|
Workhorse.debug_log("[Job worker #{id}] Logger state after reopen: #{describe_logger(logger)}")
|
|
309
309
|
|
|
310
|
-
Workhorse.debug_log("[Job worker #{id}]
|
|
310
|
+
Workhorse.debug_log("[Job worker #{id}] #{LOG_REOPEN_SIGNAL} handling complete")
|
|
311
311
|
rescue Exception => e
|
|
312
|
-
Workhorse.debug_log("[Job worker #{id}] Logger reopen failed: #{e.class}: #{e.message}")
|
|
312
|
+
Workhorse.debug_log("[Job worker #{id}] Logger reopen failed: #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}")
|
|
313
313
|
log %(Log reopen signal handler error: #{e.message}\n#{e.backtrace.join("\n")}), :error
|
|
314
314
|
Workhorse.on_exception.call(e)
|
|
315
315
|
end.join
|
|
316
316
|
end
|
|
317
|
+
Workhorse.debug_log("[Job worker #{id}] Signal handler installed: #{LOG_REOPEN_SIGNAL}")
|
|
317
318
|
end
|
|
318
319
|
|
|
319
320
|
# Sets up signal handlers for graceful termination (TERM/INT signals).
|
|
@@ -334,6 +335,7 @@ module Workhorse
|
|
|
334
335
|
end.join
|
|
335
336
|
end
|
|
336
337
|
end
|
|
338
|
+
Workhorse.debug_log("[Job worker #{id}] Signal handlers installed: #{SHUTDOWN_SIGNALS.join(', ')}")
|
|
337
339
|
end
|
|
338
340
|
|
|
339
341
|
# Initiates a soft restart of the worker.
|
|
@@ -385,6 +387,7 @@ module Workhorse
|
|
|
385
387
|
# NOTE: Unlike trap_termination, we don't join here because soft_restart
|
|
386
388
|
# is designed to be fire-and-forget (it spawns its own monitoring thread).
|
|
387
389
|
end
|
|
390
|
+
Workhorse.debug_log("[Job worker #{id}] Signal handler installed: #{SOFT_RESTART_SIGNAL}")
|
|
388
391
|
end
|
|
389
392
|
|
|
390
393
|
# Returns a human-readable description of a logger's internal state.
|
data/lib/workhorse.rb
CHANGED
|
@@ -8,6 +8,16 @@ require 'workhorse/enqueuer'
|
|
|
8
8
|
require 'workhorse/scoped_env'
|
|
9
9
|
require 'workhorse/active_job_extension'
|
|
10
10
|
|
|
11
|
+
# Prevent YJIT from being enabled when RUBY_YJIT_ENABLE is explicitly set to 0.
|
|
12
|
+
# systemd's logrotate.service typically sets MemoryDenyWriteExecute=yes, which
|
|
13
|
+
# prevents mprotect(PROT_EXEC). Rails unconditionally calls
|
|
14
|
+
# RubyVM::YJIT.enable on boot, which triggers a fatal Ruby [BUG] in that
|
|
15
|
+
# environment. Set RUBY_YJIT_ENABLE=0 in the logrotate postrotate script
|
|
16
|
+
# to prevent this.
|
|
17
|
+
if ENV['RUBY_YJIT_ENABLE'] == '0' && defined?(RubyVM::YJIT) && !RubyVM::YJIT.enabled?
|
|
18
|
+
RubyVM::YJIT.define_singleton_method(:enable) { |**| nil }
|
|
19
|
+
end
|
|
20
|
+
|
|
11
21
|
# Main Gem module.
|
|
12
22
|
module Workhorse
|
|
13
23
|
# Check if the available Arel version is greater or equal than 7.0.0
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'English'
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
require 'bundler'
|
|
4
|
+
|
|
5
|
+
class Workhorse::YjitTest < ActiveSupport::TestCase
|
|
6
|
+
YJIT_CHECK_SCRIPT = <<~RUBY.freeze
|
|
7
|
+
require 'bundler/setup'
|
|
8
|
+
require 'workhorse'
|
|
9
|
+
RubyVM::YJIT.enable
|
|
10
|
+
print RubyVM::YJIT.enabled?
|
|
11
|
+
RUBY
|
|
12
|
+
|
|
13
|
+
def test_yjit_not_enabled_when_ruby_yjit_enable_is_zero
|
|
14
|
+
skip 'RubyVM::YJIT.enable not available' unless defined?(RubyVM::YJIT) && RubyVM::YJIT.respond_to?(:enable)
|
|
15
|
+
|
|
16
|
+
# Sanity check: YJIT can actually be enabled in this environment
|
|
17
|
+
without_env = run_ruby_script(YJIT_CHECK_SCRIPT, 'RUBY_YJIT_ENABLE' => nil)
|
|
18
|
+
skip 'YJIT cannot be enabled in this environment' unless without_env == 'true'
|
|
19
|
+
|
|
20
|
+
# With RUBY_YJIT_ENABLE=0, RubyVM::YJIT.enable should be a no-op
|
|
21
|
+
with_env = run_ruby_script(YJIT_CHECK_SCRIPT, 'RUBY_YJIT_ENABLE' => '0')
|
|
22
|
+
assert_equal 'false', with_env, 'YJIT should not be enabled when RUBY_YJIT_ENABLE=0'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def run_ruby_script(script, env = {})
|
|
28
|
+
output = nil
|
|
29
|
+
Bundler.with_unbundled_env do
|
|
30
|
+
IO.popen(env, %w[bundle exec ruby -e] + [script], chdir: Rails.root.to_s, err: %i[child out]) do |io|
|
|
31
|
+
output = io.read.strip
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
assert $CHILD_STATUS.success?, "Ruby subprocess failed (exit #{$CHILD_STATUS.exitstatus}): #{output}"
|
|
35
|
+
output
|
|
36
|
+
end
|
|
37
|
+
end
|
data/workhorse.gemspec
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: workhorse 1.4.
|
|
2
|
+
# stub: workhorse 1.4.5 ruby lib
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
5
|
s.name = "workhorse".freeze
|
|
6
|
-
s.version = "1.4.
|
|
6
|
+
s.version = "1.4.5".freeze
|
|
7
7
|
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
|
9
9
|
s.require_paths = ["lib".freeze]
|
|
10
10
|
s.authors = ["Sitrox".freeze]
|
|
11
|
-
s.date = "2026-
|
|
12
|
-
s.files = [".github/workflows/ruby.yml".freeze, ".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, "CHANGELOG.md".freeze, "FAQ.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "RUBY_VERSION".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/rubocop".freeze, "lib/active_job/queue_adapters/workhorse_adapter.rb".freeze, "lib/generators/workhorse/install_generator.rb".freeze, "lib/generators/workhorse/templates/bin/workhorse.rb".freeze, "lib/generators/workhorse/templates/config/initializers/workhorse.rb".freeze, "lib/generators/workhorse/templates/create_table_jobs.rb".freeze, "lib/workhorse.rb".freeze, "lib/workhorse/active_job_extension.rb".freeze, "lib/workhorse/daemon.rb".freeze, "lib/workhorse/daemon/shell_handler.rb".freeze, "lib/workhorse/db_job.rb".freeze, "lib/workhorse/enqueuer.rb".freeze, "lib/workhorse/jobs/cleanup_succeeded_jobs.rb".freeze, "lib/workhorse/jobs/detect_stale_jobs_job.rb".freeze, "lib/workhorse/jobs/run_active_job.rb".freeze, "lib/workhorse/jobs/run_rails_op.rb".freeze, "lib/workhorse/performer.rb".freeze, "lib/workhorse/poller.rb".freeze, "lib/workhorse/pool.rb".freeze, "lib/workhorse/scoped_env.rb".freeze, "lib/workhorse/worker.rb".freeze, "test/active_job/queue_adapters/workhorse_adapter_test.rb".freeze, "test/lib/db_schema.rb".freeze, "test/lib/jobs.rb".freeze, "test/lib/test_helper.rb".freeze, "test/workhorse/daemon_test.rb".freeze, "test/workhorse/db_job_test.rb".freeze, "test/workhorse/enqueuer_test.rb".freeze, "test/workhorse/performer_test.rb".freeze, "test/workhorse/poller_test.rb".freeze, "test/workhorse/pool_test.rb".freeze, "test/workhorse/worker_test.rb".freeze, "workhorse.gemspec".freeze]
|
|
11
|
+
s.date = "2026-05-09"
|
|
12
|
+
s.files = [".github/workflows/ruby.yml".freeze, ".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, "CHANGELOG.md".freeze, "FAQ.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "RUBY_VERSION".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/rubocop".freeze, "lib/active_job/queue_adapters/workhorse_adapter.rb".freeze, "lib/generators/workhorse/install_generator.rb".freeze, "lib/generators/workhorse/templates/bin/workhorse.rb".freeze, "lib/generators/workhorse/templates/config/initializers/workhorse.rb".freeze, "lib/generators/workhorse/templates/create_table_jobs.rb".freeze, "lib/workhorse.rb".freeze, "lib/workhorse/active_job_extension.rb".freeze, "lib/workhorse/daemon.rb".freeze, "lib/workhorse/daemon/shell_handler.rb".freeze, "lib/workhorse/db_job.rb".freeze, "lib/workhorse/enqueuer.rb".freeze, "lib/workhorse/jobs/cleanup_succeeded_jobs.rb".freeze, "lib/workhorse/jobs/detect_stale_jobs_job.rb".freeze, "lib/workhorse/jobs/run_active_job.rb".freeze, "lib/workhorse/jobs/run_rails_op.rb".freeze, "lib/workhorse/performer.rb".freeze, "lib/workhorse/poller.rb".freeze, "lib/workhorse/pool.rb".freeze, "lib/workhorse/scoped_env.rb".freeze, "lib/workhorse/worker.rb".freeze, "test/active_job/queue_adapters/workhorse_adapter_test.rb".freeze, "test/lib/db_schema.rb".freeze, "test/lib/jobs.rb".freeze, "test/lib/test_helper.rb".freeze, "test/workhorse/daemon_test.rb".freeze, "test/workhorse/db_job_test.rb".freeze, "test/workhorse/enqueuer_test.rb".freeze, "test/workhorse/performer_test.rb".freeze, "test/workhorse/poller_test.rb".freeze, "test/workhorse/pool_test.rb".freeze, "test/workhorse/worker_test.rb".freeze, "test/workhorse/yjit_test.rb".freeze, "workhorse.gemspec".freeze]
|
|
13
13
|
s.homepage = "https://github.com/sitrox/workhorse".freeze
|
|
14
14
|
s.licenses = ["MIT".freeze]
|
|
15
|
-
s.rubygems_version = "3.
|
|
15
|
+
s.rubygems_version = "3.5.18".freeze
|
|
16
16
|
s.summary = "Multi-threaded job backend with database queuing for ruby.".freeze
|
|
17
|
-
s.test_files = ["test/active_job/queue_adapters/workhorse_adapter_test.rb".freeze, "test/lib/db_schema.rb".freeze, "test/lib/jobs.rb".freeze, "test/lib/test_helper.rb".freeze, "test/workhorse/daemon_test.rb".freeze, "test/workhorse/db_job_test.rb".freeze, "test/workhorse/enqueuer_test.rb".freeze, "test/workhorse/performer_test.rb".freeze, "test/workhorse/poller_test.rb".freeze, "test/workhorse/pool_test.rb".freeze, "test/workhorse/worker_test.rb".freeze]
|
|
17
|
+
s.test_files = ["test/active_job/queue_adapters/workhorse_adapter_test.rb".freeze, "test/lib/db_schema.rb".freeze, "test/lib/jobs.rb".freeze, "test/lib/test_helper.rb".freeze, "test/workhorse/daemon_test.rb".freeze, "test/workhorse/db_job_test.rb".freeze, "test/workhorse/enqueuer_test.rb".freeze, "test/workhorse/performer_test.rb".freeze, "test/workhorse/poller_test.rb".freeze, "test/workhorse/pool_test.rb".freeze, "test/workhorse/worker_test.rb".freeze, "test/workhorse/yjit_test.rb".freeze]
|
|
18
18
|
|
|
19
19
|
s.specification_version = 4
|
|
20
20
|
|
|
21
|
-
s.add_runtime_dependency(%q<activesupport>.freeze, [">= 7.0.0"])
|
|
22
|
-
s.add_runtime_dependency(%q<activerecord>.freeze, [">= 7.0.0"])
|
|
23
|
-
s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 0"])
|
|
21
|
+
s.add_runtime_dependency(%q<activesupport>.freeze, [">= 7.0.0".freeze])
|
|
22
|
+
s.add_runtime_dependency(%q<activerecord>.freeze, [">= 7.0.0".freeze])
|
|
23
|
+
s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 0".freeze])
|
|
24
24
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: workhorse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.4.
|
|
4
|
+
version: 1.4.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sitrox
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-05-09 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activesupport
|
|
@@ -99,6 +99,7 @@ files:
|
|
|
99
99
|
- test/workhorse/poller_test.rb
|
|
100
100
|
- test/workhorse/pool_test.rb
|
|
101
101
|
- test/workhorse/worker_test.rb
|
|
102
|
+
- test/workhorse/yjit_test.rb
|
|
102
103
|
- workhorse.gemspec
|
|
103
104
|
homepage: https://github.com/sitrox/workhorse
|
|
104
105
|
licenses:
|
|
@@ -133,3 +134,4 @@ test_files:
|
|
|
133
134
|
- test/workhorse/poller_test.rb
|
|
134
135
|
- test/workhorse/pool_test.rb
|
|
135
136
|
- test/workhorse/worker_test.rb
|
|
137
|
+
- test/workhorse/yjit_test.rb
|