workhorse 1.4.0 → 1.4.1
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 +16 -0
- data/VERSION +1 -1
- data/lib/workhorse/daemon/shell_handler.rb +28 -5
- data/lib/workhorse/daemon.rb +6 -0
- data/lib/workhorse/worker.rb +4 -1
- 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: df386a01e22eb4d5e05be449ef11a62341d28c3443fdef76b07ac7e8bca3e3d4
|
|
4
|
+
data.tar.gz: 0a4f325c0bf2cb08357a195a2297d0302df275abf3cd6d83329942d68419f7c8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 12b8ec75c276bf6d888e3f60b523a32cc387c6c4a935b20004fce4f63acbc4e7046979315eb7c6651953177d7289a3bf27fabc535da117a3d6a9c7be36f17ccd
|
|
7
|
+
data.tar.gz: 1d15f6cf25a9fe2878e9edf45a7b2ce69d0bf0904119efd2d6234e8c15dc7142ce81c427912f22f2459fa27967b58932497424646d5ea9af431d625a1e154a8a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Workhorse Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.1 - 2026-02-18
|
|
4
|
+
|
|
5
|
+
* Close inherited lockfile fd in forked worker processes. Previously the
|
|
6
|
+
lockfile's file descriptor was inherited by children via `fork`, which could
|
|
7
|
+
prevent the POSIX `flock` from being released if the daemon process exited
|
|
8
|
+
abnormally.
|
|
9
|
+
|
|
10
|
+
* Fix `watch` and `kill` commands to actually abort when the lock is
|
|
11
|
+
unavailable. Previously the `flock` return value with `LOCK_NB` was not
|
|
12
|
+
checked, so the commands would silently proceed without the lock.
|
|
13
|
+
|
|
14
|
+
* Add error handling to the `HUP` signal handler for log reopening. Exceptions
|
|
15
|
+
from `logger.reopen` are now caught and reported via `on_exception`.
|
|
16
|
+
|
|
17
|
+
Sitrox reference: #120574.
|
|
18
|
+
|
|
3
19
|
## 1.4.0 - 2026-02-12
|
|
4
20
|
|
|
5
21
|
* Stable release based on previous RC release.
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.4.
|
|
1
|
+
1.4.1
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module Workhorse
|
|
2
2
|
class Daemon::ShellHandler
|
|
3
|
+
class LockNotAvailableError < StandardError; end
|
|
4
|
+
|
|
3
5
|
def self.run(**options, &block)
|
|
4
6
|
unless ARGV.one?
|
|
5
7
|
usage
|
|
@@ -15,27 +17,43 @@ module Workhorse
|
|
|
15
17
|
case ARGV.first
|
|
16
18
|
when 'start'
|
|
17
19
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
20
|
+
daemon.lockfile = lockfile
|
|
18
21
|
status = daemon.start
|
|
19
22
|
when 'stop'
|
|
20
23
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
24
|
+
daemon.lockfile = lockfile
|
|
21
25
|
status = daemon.stop
|
|
22
26
|
when 'kill'
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
begin
|
|
28
|
+
lockfile = acquire_lock(lockfile_path, File::LOCK_EX | File::LOCK_NB)
|
|
29
|
+
daemon.lockfile = lockfile
|
|
30
|
+
status = daemon.stop(true)
|
|
31
|
+
rescue LockNotAvailableError
|
|
32
|
+
status = 1
|
|
33
|
+
end
|
|
25
34
|
when 'status'
|
|
26
35
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
36
|
+
daemon.lockfile = lockfile
|
|
27
37
|
status = daemon.status
|
|
28
38
|
when 'watch'
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
begin
|
|
40
|
+
lockfile = acquire_lock(lockfile_path, File::LOCK_EX | File::LOCK_NB)
|
|
41
|
+
daemon.lockfile = lockfile
|
|
42
|
+
status = daemon.watch
|
|
43
|
+
rescue LockNotAvailableError
|
|
44
|
+
status = 1
|
|
45
|
+
end
|
|
31
46
|
when 'restart'
|
|
32
47
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
48
|
+
daemon.lockfile = lockfile
|
|
33
49
|
status = daemon.restart
|
|
34
50
|
when 'restart-logging'
|
|
35
51
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
52
|
+
daemon.lockfile = lockfile
|
|
36
53
|
status = daemon.restart_logging
|
|
37
54
|
when 'soft-restart'
|
|
38
55
|
lockfile = acquire_lock(lockfile_path, File::LOCK_EX)
|
|
56
|
+
daemon.lockfile = lockfile
|
|
39
57
|
status = daemon.soft_restart
|
|
40
58
|
when 'usage'
|
|
41
59
|
usage
|
|
@@ -105,7 +123,12 @@ module Workhorse
|
|
|
105
123
|
def self.acquire_lock(lockfile_path, flags)
|
|
106
124
|
if Workhorse.lock_shell_commands
|
|
107
125
|
lockfile = File.open(lockfile_path, 'a')
|
|
108
|
-
lockfile.flock(flags)
|
|
126
|
+
result = lockfile.flock(flags)
|
|
127
|
+
|
|
128
|
+
if result == false
|
|
129
|
+
lockfile.close
|
|
130
|
+
fail LockNotAvailableError, 'Could not acquire lock. Is another workhorse command already running?'
|
|
131
|
+
end
|
|
109
132
|
|
|
110
133
|
return lockfile
|
|
111
134
|
end
|
data/lib/workhorse/daemon.rb
CHANGED
|
@@ -34,6 +34,10 @@ module Workhorse
|
|
|
34
34
|
# @private
|
|
35
35
|
attr_reader :workers
|
|
36
36
|
|
|
37
|
+
# @return [File, nil] Lockfile handle to close in forked children
|
|
38
|
+
# @private
|
|
39
|
+
attr_accessor :lockfile
|
|
40
|
+
|
|
37
41
|
# Creates a new daemon instance.
|
|
38
42
|
#
|
|
39
43
|
# @param pidfile [String, nil] Path template for PID files (use %i placeholder for worker ID)
|
|
@@ -261,6 +265,8 @@ module Workhorse
|
|
|
261
265
|
|
|
262
266
|
pid = fork do
|
|
263
267
|
$0 = process_name(worker)
|
|
268
|
+
# Close inherited lockfile fd to prevent holding the flock after parent exits
|
|
269
|
+
@lockfile&.close
|
|
264
270
|
# Reopen pipes to prevent #107576
|
|
265
271
|
$stdin.reopen File.open(File::NULL, 'r')
|
|
266
272
|
null_out = File.open File::NULL, 'w'
|
data/lib/workhorse/worker.rb
CHANGED
|
@@ -296,11 +296,14 @@ module Workhorse
|
|
|
296
296
|
def trap_log_reopen
|
|
297
297
|
Signal.trap(LOG_REOPEN_SIGNAL) do
|
|
298
298
|
Thread.new do
|
|
299
|
-
logger
|
|
299
|
+
logger&.reopen
|
|
300
300
|
|
|
301
301
|
if defined?(ActiveRecord::Base) && ActiveRecord::Base.logger && ActiveRecord::Base.logger != logger
|
|
302
302
|
ActiveRecord::Base.logger.reopen
|
|
303
303
|
end
|
|
304
|
+
rescue Exception => e
|
|
305
|
+
log %(Log reopen signal handler error: #{e.message}\n#{e.backtrace.join("\n")}), :error
|
|
306
|
+
Workhorse.on_exception.call(e)
|
|
304
307
|
end.join
|
|
305
308
|
end
|
|
306
309
|
end
|
data/workhorse.gemspec
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: workhorse 1.4.
|
|
2
|
+
# stub: workhorse 1.4.1 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.1"
|
|
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-18"
|
|
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.1
|
|
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-18 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activesupport
|