workhorse 1.4.1 → 1.4.2
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 +12 -0
- data/README.md +17 -1
- data/VERSION +1 -1
- data/lib/workhorse/daemon/shell_handler.rb +22 -1
- data/lib/workhorse/daemon.rb +23 -0
- data/lib/workhorse/worker.rb +55 -4
- data/lib/workhorse.rb +25 -0
- data/workhorse.gemspec +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0facaea70a5e826980ea41034914a0609a22fb3ed93c9fbe4a7607eb5a3854c9
|
|
4
|
+
data.tar.gz: 35cc28b0a31206fa5f38df60858c5c2054c28fd7c47a4bf0b4983c9cbbcc02d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 551453702ecb4b89060a7e5fdba4639eccbb60c09c85ebd2fd561eec91787c1b8166be81e81b2bd2da46f250ba70c8426198bca404d1cf1e5fbf1c6c9b5096ee
|
|
7
|
+
data.tar.gz: e1ee8b9ae1267271f8be2befd5455d90614e02c8708b2413bc90f957b8d5fb852b2f805ea4d42b6362844c2e7ed774e2a0a727e83687d570d0c430174e264227
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Workhorse Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.2 - 2026-02-20
|
|
4
|
+
|
|
5
|
+
* Detach forked worker processes into their own session using `Process.setsid`.
|
|
6
|
+
Previously, when the ShellHandler was the session leader (e.g. started via
|
|
7
|
+
cron), its exit would cause the kernel to send `SIGHUP` to all forked workers,
|
|
8
|
+
potentially crashing them during startup before signal handlers were installed.
|
|
9
|
+
|
|
10
|
+
* Add optional debug logging (`config.debug_log_path`) for diagnosing issues
|
|
11
|
+
with signal handling, process lifecycle, log rotation, and daemon commands.
|
|
12
|
+
|
|
13
|
+
Sitrox reference: #120574.
|
|
14
|
+
|
|
3
15
|
## 1.4.1 - 2026-02-18
|
|
4
16
|
|
|
5
17
|
* Close inherited lockfile fd in forked worker processes. Previously the
|
data/README.md
CHANGED
|
@@ -522,7 +522,6 @@ Gem-internal model class `Workhorse::DbJob`, for example:
|
|
|
522
522
|
|
|
523
523
|
```ruby
|
|
524
524
|
# config/initializers/workhorse.rb
|
|
525
|
-
|
|
526
525
|
ActiveSupport.on_load :workhorse_db_job do
|
|
527
526
|
# Code within this block will be run inside of the model class
|
|
528
527
|
# Workhorse::DbJob.
|
|
@@ -530,6 +529,23 @@ ActiveSupport.on_load :workhorse_db_job do
|
|
|
530
529
|
end
|
|
531
530
|
```
|
|
532
531
|
|
|
532
|
+
## Debug logging
|
|
533
|
+
|
|
534
|
+
Workhorse includes an optional debug log for diagnosing issues with signal
|
|
535
|
+
handling, process lifecycle, log rotation, and daemon commands. To enable,
|
|
536
|
+
set `debug_log_path` to a writable file path:
|
|
537
|
+
|
|
538
|
+
```ruby
|
|
539
|
+
# config/initializers/workhorse.rb
|
|
540
|
+
Workhorse.setup do |config|
|
|
541
|
+
config.debug_log_path = Rails.root.join('log', 'workhorse.debug.log')
|
|
542
|
+
end
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
The debug log is designed to be safe for production use: all writes are
|
|
546
|
+
best-effort and silently ignore errors to avoid interfering with normal
|
|
547
|
+
operation. Set `debug_log_path` to `nil` (the default) to disable.
|
|
548
|
+
|
|
533
549
|
## Caveats
|
|
534
550
|
|
|
535
551
|
### Errors during polling / crashed workers
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.4.
|
|
1
|
+
1.4.2
|
|
@@ -16,43 +16,61 @@ module Workhorse
|
|
|
16
16
|
begin
|
|
17
17
|
case ARGV.first
|
|
18
18
|
when 'start'
|
|
19
|
+
Workhorse.debug_log('ShellHandler: start command invoked')
|
|
19
20
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
21
|
+
Workhorse.debug_log('ShellHandler: lock acquired for start')
|
|
20
22
|
daemon.lockfile = lockfile
|
|
21
23
|
status = daemon.start
|
|
22
24
|
when 'stop'
|
|
25
|
+
Workhorse.debug_log('ShellHandler: stop command invoked')
|
|
23
26
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
27
|
+
Workhorse.debug_log('ShellHandler: lock acquired for stop')
|
|
24
28
|
daemon.lockfile = lockfile
|
|
25
29
|
status = daemon.stop
|
|
26
30
|
when 'kill'
|
|
31
|
+
Workhorse.debug_log('ShellHandler: kill command invoked')
|
|
27
32
|
begin
|
|
28
33
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX | File::LOCK_NB)
|
|
34
|
+
Workhorse.debug_log('ShellHandler: lock acquired for kill')
|
|
29
35
|
daemon.lockfile = lockfile
|
|
30
36
|
status = daemon.stop(true)
|
|
31
37
|
rescue LockNotAvailableError
|
|
38
|
+
Workhorse.debug_log('ShellHandler: lock not available for kill')
|
|
32
39
|
status = 1
|
|
33
40
|
end
|
|
34
41
|
when 'status'
|
|
42
|
+
Workhorse.debug_log('ShellHandler: status command invoked')
|
|
35
43
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
44
|
+
Workhorse.debug_log('ShellHandler: lock acquired for status')
|
|
36
45
|
daemon.lockfile = lockfile
|
|
37
46
|
status = daemon.status
|
|
38
47
|
when 'watch'
|
|
48
|
+
Workhorse.debug_log('ShellHandler: watch command invoked')
|
|
39
49
|
begin
|
|
40
50
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX | File::LOCK_NB)
|
|
51
|
+
Workhorse.debug_log('ShellHandler: lock acquired for watch')
|
|
41
52
|
daemon.lockfile = lockfile
|
|
42
53
|
status = daemon.watch
|
|
43
54
|
rescue LockNotAvailableError
|
|
55
|
+
Workhorse.debug_log('ShellHandler: lock not available for watch')
|
|
44
56
|
status = 1
|
|
45
57
|
end
|
|
46
58
|
when 'restart'
|
|
59
|
+
Workhorse.debug_log('ShellHandler: restart command invoked')
|
|
47
60
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
61
|
+
Workhorse.debug_log('ShellHandler: lock acquired for restart')
|
|
48
62
|
daemon.lockfile = lockfile
|
|
49
63
|
status = daemon.restart
|
|
50
64
|
when 'restart-logging'
|
|
65
|
+
Workhorse.debug_log('ShellHandler: restart-logging command invoked')
|
|
51
66
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
67
|
+
Workhorse.debug_log('ShellHandler: lock acquired for restart-logging')
|
|
52
68
|
daemon.lockfile = lockfile
|
|
53
69
|
status = daemon.restart_logging
|
|
54
70
|
when 'soft-restart'
|
|
71
|
+
Workhorse.debug_log('ShellHandler: soft-restart command invoked')
|
|
55
72
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
73
|
+
Workhorse.debug_log('ShellHandler: lock acquired for soft-restart')
|
|
56
74
|
daemon.lockfile = lockfile
|
|
57
75
|
status = daemon.soft_restart
|
|
58
76
|
when 'usage'
|
|
@@ -66,7 +84,10 @@ module Workhorse
|
|
|
66
84
|
warn "#{e.message}\n#{e.backtrace.join("\n")}"
|
|
67
85
|
status = 99
|
|
68
86
|
ensure
|
|
69
|
-
lockfile
|
|
87
|
+
if lockfile
|
|
88
|
+
Workhorse.debug_log("ShellHandler: releasing lock for #{ARGV.first}")
|
|
89
|
+
lockfile.flock(File::LOCK_UN)
|
|
90
|
+
end
|
|
70
91
|
exit! status
|
|
71
92
|
end
|
|
72
93
|
end
|
data/lib/workhorse/daemon.rb
CHANGED
|
@@ -201,20 +201,27 @@ module Workhorse
|
|
|
201
201
|
def restart_logging
|
|
202
202
|
code = 0
|
|
203
203
|
|
|
204
|
+
Workhorse.debug_log("restart_logging: sending HUP to #{@workers.count} worker(s)")
|
|
205
|
+
|
|
204
206
|
for_each_worker do |worker|
|
|
205
207
|
_pid_file, pid, active = read_pid(worker)
|
|
206
208
|
|
|
209
|
+
Workhorse.debug_log("restart_logging: worker ##{worker.id} (#{worker.name}): pid=#{pid.inspect}, active=#{active.inspect}")
|
|
210
|
+
|
|
207
211
|
next unless pid && active
|
|
208
212
|
|
|
209
213
|
begin
|
|
210
214
|
Process.kill 'HUP', pid
|
|
215
|
+
Workhorse.debug_log("restart_logging: HUP sent successfully to PID #{pid}")
|
|
211
216
|
puts "Worker (#{worker.name}) ##{worker.id}: Sent signal for restart-logging"
|
|
212
217
|
rescue Errno::ESRCH
|
|
218
|
+
Workhorse.debug_log("restart_logging: HUP failed for PID #{pid}: process not found")
|
|
213
219
|
warn "Worker (#{worker.name}) ##{worker.id}: Could not send signal for restart-logging, process not found"
|
|
214
220
|
code = 2
|
|
215
221
|
end
|
|
216
222
|
end
|
|
217
223
|
|
|
224
|
+
Workhorse.debug_log("restart_logging: done, exit code=#{code}")
|
|
218
225
|
return code
|
|
219
226
|
end
|
|
220
227
|
|
|
@@ -227,20 +234,27 @@ module Workhorse
|
|
|
227
234
|
def soft_restart
|
|
228
235
|
code = 0
|
|
229
236
|
|
|
237
|
+
Workhorse.debug_log("Daemon: sending USR1 to #{@workers.count} worker(s)")
|
|
238
|
+
|
|
230
239
|
for_each_worker do |worker|
|
|
231
240
|
_pid_file, pid, active = read_pid(worker)
|
|
232
241
|
|
|
242
|
+
Workhorse.debug_log("Daemon soft_restart: worker ##{worker.id} (#{worker.name}): pid=#{pid.inspect}, active=#{active.inspect}")
|
|
243
|
+
|
|
233
244
|
next unless pid && active
|
|
234
245
|
|
|
235
246
|
begin
|
|
236
247
|
Process.kill 'USR1', pid
|
|
248
|
+
Workhorse.debug_log("Daemon: USR1 sent successfully to PID #{pid}")
|
|
237
249
|
puts "Worker (#{worker.name}) ##{worker.id}: Sent soft-restart signal"
|
|
238
250
|
rescue Errno::ESRCH
|
|
251
|
+
Workhorse.debug_log("Daemon: USR1 failed for PID #{pid}: process not found")
|
|
239
252
|
warn "Worker (#{worker.name}) ##{worker.id}: Process not found"
|
|
240
253
|
code = 2
|
|
241
254
|
end
|
|
242
255
|
end
|
|
243
256
|
|
|
257
|
+
Workhorse.debug_log("Daemon soft_restart: done, exit code=#{code}")
|
|
244
258
|
return code
|
|
245
259
|
end
|
|
246
260
|
|
|
@@ -263,7 +277,13 @@ module Workhorse
|
|
|
263
277
|
def start_worker(worker)
|
|
264
278
|
check_rails_env if defined?(Rails)
|
|
265
279
|
|
|
280
|
+
Workhorse.debug_log("Daemon: forking worker ##{worker.id} (#{worker.name})")
|
|
266
281
|
pid = fork do
|
|
282
|
+
# Detach from the parent's session so that the worker is not killed by
|
|
283
|
+
# SIGHUP when the parent (ShellHandler) exits. Without this, the kernel
|
|
284
|
+
# sends SIGHUP to the foreground process group when the session leader
|
|
285
|
+
# (e.g. a cron- or systemd-started ShellHandler) terminates.
|
|
286
|
+
Process.setsid
|
|
267
287
|
$0 = process_name(worker)
|
|
268
288
|
# Close inherited lockfile fd to prevent holding the flock after parent exits
|
|
269
289
|
@lockfile&.close
|
|
@@ -278,6 +298,7 @@ module Workhorse
|
|
|
278
298
|
worker.pid = pid
|
|
279
299
|
File.write(pid_file_for(worker), pid)
|
|
280
300
|
Process.detach(pid)
|
|
301
|
+
Workhorse.debug_log("Daemon: worker ##{worker.id} (#{worker.name}) forked with PID #{pid}")
|
|
281
302
|
end
|
|
282
303
|
|
|
283
304
|
# Stops a single worker process.
|
|
@@ -290,6 +311,7 @@ module Workhorse
|
|
|
290
311
|
def stop_worker(pid_file, pid, kill: false)
|
|
291
312
|
signals = kill ? %w[KILL] : %w[TERM INT]
|
|
292
313
|
|
|
314
|
+
Workhorse.debug_log("Daemon: stopping PID #{pid} with signals #{signals.join(', ')}")
|
|
293
315
|
loop do
|
|
294
316
|
begin
|
|
295
317
|
signals.each { |signal| Process.kill(signal, pid) }
|
|
@@ -300,6 +322,7 @@ module Workhorse
|
|
|
300
322
|
sleep 1
|
|
301
323
|
end
|
|
302
324
|
|
|
325
|
+
Workhorse.debug_log("Daemon: PID #{pid} stopped")
|
|
303
326
|
File.delete(pid_file)
|
|
304
327
|
end
|
|
305
328
|
|
data/lib/workhorse/worker.rb
CHANGED
|
@@ -158,6 +158,8 @@ module Workhorse
|
|
|
158
158
|
@poller.start
|
|
159
159
|
log 'Started up'
|
|
160
160
|
|
|
161
|
+
Workhorse.debug_log("[Job worker #{id}] Started: PID=#{pid}, logger=#{describe_logger(logger)}")
|
|
162
|
+
|
|
161
163
|
trap_termination if @auto_terminate
|
|
162
164
|
trap_log_reopen
|
|
163
165
|
trap_soft_restart
|
|
@@ -189,12 +191,14 @@ module Workhorse
|
|
|
189
191
|
mutex.synchronize do
|
|
190
192
|
assert_state! :running
|
|
191
193
|
|
|
194
|
+
Workhorse.debug_log("[Job worker #{id}] Shutdown starting")
|
|
192
195
|
log 'Shutting down'
|
|
193
196
|
@state = :shutdown
|
|
194
197
|
|
|
195
198
|
@poller.shutdown
|
|
196
199
|
@pool.shutdown
|
|
197
200
|
log 'Shut down'
|
|
201
|
+
Workhorse.debug_log("[Job worker #{id}] Shutdown complete")
|
|
198
202
|
end
|
|
199
203
|
end
|
|
200
204
|
|
|
@@ -267,6 +271,8 @@ module Workhorse
|
|
|
267
271
|
|
|
268
272
|
return true unless exceeded
|
|
269
273
|
|
|
274
|
+
Workhorse.debug_log("[Job worker #{id}] Memory limit exceeded: #{mem}MB > #{max}MB, initiating shutdown")
|
|
275
|
+
|
|
270
276
|
if defined?(Rails)
|
|
271
277
|
FileUtils.touch self.class.shutdown_file_for(pid)
|
|
272
278
|
end
|
|
@@ -296,12 +302,14 @@ module Workhorse
|
|
|
296
302
|
def trap_log_reopen
|
|
297
303
|
Signal.trap(LOG_REOPEN_SIGNAL) do
|
|
298
304
|
Thread.new do
|
|
305
|
+
Workhorse.debug_log("[Job worker #{id}] HUP received, logger state before reopen: #{describe_logger(logger)}")
|
|
306
|
+
|
|
299
307
|
logger&.reopen
|
|
308
|
+
Workhorse.debug_log("[Job worker #{id}] Logger state after reopen: #{describe_logger(logger)}")
|
|
300
309
|
|
|
301
|
-
|
|
302
|
-
ActiveRecord::Base.logger.reopen
|
|
303
|
-
end
|
|
310
|
+
Workhorse.debug_log("[Job worker #{id}] HUP handling complete")
|
|
304
311
|
rescue Exception => e
|
|
312
|
+
Workhorse.debug_log("[Job worker #{id}] Logger reopen failed: #{e.class}: #{e.message}")
|
|
305
313
|
log %(Log reopen signal handler error: #{e.message}\n#{e.backtrace.join("\n")}), :error
|
|
306
314
|
Workhorse.on_exception.call(e)
|
|
307
315
|
end.join
|
|
@@ -320,6 +328,7 @@ module Workhorse
|
|
|
320
328
|
# quickly when called multiple times, this does not pose a risk of
|
|
321
329
|
# keeping open a big number of "shutdown threads".
|
|
322
330
|
Thread.new do
|
|
331
|
+
Workhorse.debug_log("[Job worker #{id}] #{signal} received, shutting down")
|
|
323
332
|
log "\nCaught #{signal}, shutting worker down..."
|
|
324
333
|
shutdown
|
|
325
334
|
end.join
|
|
@@ -339,9 +348,14 @@ module Workhorse
|
|
|
339
348
|
|
|
340
349
|
return unless @soft_restart_requested.make_true
|
|
341
350
|
|
|
351
|
+
Workhorse.debug_log("[Job worker #{id}] Soft restart initiated")
|
|
352
|
+
|
|
342
353
|
# Create shutdown file for watch to detect
|
|
343
354
|
shutdown_file = self.class.shutdown_file_for(pid)
|
|
344
|
-
|
|
355
|
+
if shutdown_file
|
|
356
|
+
FileUtils.touch(shutdown_file)
|
|
357
|
+
Workhorse.debug_log("[Job worker #{id}] Shutdown file created: #{shutdown_file}")
|
|
358
|
+
end
|
|
345
359
|
|
|
346
360
|
# Monitor in a separate thread to avoid blocking the signal handler
|
|
347
361
|
@soft_restart_thread = Thread.new do
|
|
@@ -361,6 +375,7 @@ module Workhorse
|
|
|
361
375
|
# Start a new thread as certain functionality (such as logging) is not
|
|
362
376
|
# available from within a trap context.
|
|
363
377
|
Thread.new do
|
|
378
|
+
Workhorse.debug_log("[Job worker #{id}] #{SOFT_RESTART_SIGNAL} received, initiating soft restart")
|
|
364
379
|
log "\nCaught #{SOFT_RESTART_SIGNAL}, initiating soft restart..."
|
|
365
380
|
soft_restart
|
|
366
381
|
rescue Exception => e
|
|
@@ -372,16 +387,52 @@ module Workhorse
|
|
|
372
387
|
end
|
|
373
388
|
end
|
|
374
389
|
|
|
390
|
+
# Returns a human-readable description of a logger's internal state.
|
|
391
|
+
# Used for debug logging to diagnose log rotation issues.
|
|
392
|
+
#
|
|
393
|
+
# @param lgr [Logger, nil] The logger to describe
|
|
394
|
+
# @return [String] Description of the logger's state
|
|
395
|
+
# @private
|
|
396
|
+
def describe_logger(lgr)
|
|
397
|
+
return 'nil' unless lgr
|
|
398
|
+
|
|
399
|
+
parts = ["class=#{lgr.class}"]
|
|
400
|
+
|
|
401
|
+
logdev = lgr.instance_variable_get(:@logdev)
|
|
402
|
+
if logdev
|
|
403
|
+
parts << "filename=#{logdev.filename.inspect}" if logdev.respond_to?(:filename)
|
|
404
|
+
|
|
405
|
+
dev = logdev.respond_to?(:dev) ? logdev.dev : nil
|
|
406
|
+
if dev
|
|
407
|
+
parts << "closed=#{dev.closed?}"
|
|
408
|
+
unless dev.closed?
|
|
409
|
+
fileno = dev.fileno
|
|
410
|
+
parts << "fd=#{fileno}"
|
|
411
|
+
fd_path = "/proc/self/fd/#{fileno}"
|
|
412
|
+
parts << "fd_target=#{File.readlink(fd_path).inspect}" if File.exist?(fd_path)
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
else
|
|
416
|
+
parts << 'logdev=nil'
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
parts.join(', ')
|
|
420
|
+
rescue Exception => e
|
|
421
|
+
"error describing logger: #{e.class}: #{e.message}"
|
|
422
|
+
end
|
|
423
|
+
|
|
375
424
|
# Waits for all jobs to complete, then shuts down the worker.
|
|
376
425
|
# Called asynchronously from soft_restart.
|
|
377
426
|
#
|
|
378
427
|
# @return [void]
|
|
379
428
|
# @private
|
|
380
429
|
def wait_for_idle_then_shutdown
|
|
430
|
+
Workhorse.debug_log("[Job worker #{id}] Waiting for idle before soft restart shutdown (pool_size=#{@pool_size})")
|
|
381
431
|
loop do
|
|
382
432
|
break if @state == :shutdown
|
|
383
433
|
|
|
384
434
|
if idle == @pool_size
|
|
435
|
+
Workhorse.debug_log("[Job worker #{id}] All threads idle, proceeding with soft restart shutdown")
|
|
385
436
|
log 'All jobs completed, shutting down for soft restart'
|
|
386
437
|
shutdown
|
|
387
438
|
break
|
data/lib/workhorse.rb
CHANGED
|
@@ -107,6 +107,31 @@ module Workhorse
|
|
|
107
107
|
mattr_accessor :max_worker_memory_mb
|
|
108
108
|
self.max_worker_memory_mb = 0
|
|
109
109
|
|
|
110
|
+
# Path to a debug log file for diagnosing log rotation and signal handling issues.
|
|
111
|
+
# When set, Workhorse writes timestamped debug entries to this file at key points
|
|
112
|
+
# (worker startup, HUP signal handling, restart-logging command flow).
|
|
113
|
+
# Set to nil to disable (default).
|
|
114
|
+
#
|
|
115
|
+
# @return [String, nil] Path to debug log file
|
|
116
|
+
mattr_accessor :debug_log_path
|
|
117
|
+
self.debug_log_path = nil
|
|
118
|
+
|
|
119
|
+
# Writes a debug message to the debug log file.
|
|
120
|
+
# Does nothing if {.debug_log_path} is nil.
|
|
121
|
+
# Silently ignores all exceptions to avoid interfering with normal operation.
|
|
122
|
+
#
|
|
123
|
+
# @param message [String] The message to log
|
|
124
|
+
# @return [void]
|
|
125
|
+
def self.debug_log(message)
|
|
126
|
+
return unless debug_log_path
|
|
127
|
+
|
|
128
|
+
File.open(debug_log_path, 'a') do |f|
|
|
129
|
+
f.write("[#{Time.now.iso8601(3)}] [PID #{Process.pid}] #{message}\n")
|
|
130
|
+
f.flush
|
|
131
|
+
end
|
|
132
|
+
rescue Exception # rubocop:disable Lint/SuppressedException
|
|
133
|
+
end
|
|
134
|
+
|
|
110
135
|
# Configuration method for setting up Workhorse options.
|
|
111
136
|
#
|
|
112
137
|
# @yield [self] Configuration block
|
data/workhorse.gemspec
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: workhorse 1.4.
|
|
2
|
+
# stub: workhorse 1.4.2 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.2"
|
|
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-02-
|
|
11
|
+
s.date = "2026-02-20"
|
|
12
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]
|
|
13
13
|
s.homepage = "https://github.com/sitrox/workhorse".freeze
|
|
14
14
|
s.licenses = ["MIT".freeze]
|
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.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sitrox
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-02-
|
|
10
|
+
date: 2026-02-20 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activesupport
|