workhorse 1.2.4 → 1.2.7
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/.github/workflows/ruby.yml +36 -0
- data/CHANGELOG.md +21 -0
- data/LICENSE +1 -1
- data/README.md +10 -5
- data/VERSION +1 -1
- data/lib/workhorse/daemon/shell_handler.rb +9 -2
- data/lib/workhorse/daemon.rb +26 -4
- data/lib/workhorse/jobs/detect_stale_jobs_job.rb +15 -11
- data/lib/workhorse/worker.rb +14 -0
- data/lib/workhorse.rb +12 -0
- data/test/active_job/queue_adapters/workhorse_adapter_test.rb +1 -1
- data/test/lib/test_helper.rb +1 -1
- data/test/workhorse/pool_test.rb +3 -3
- data/workhorse.gemspec +4 -4
- metadata +4 -4
- data/.travis.yml +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36904c2ff67ab30f876e47515dfd81ccb97715a6e3d563ba93bd59422374d660
|
4
|
+
data.tar.gz: 0c9c66eb75727e78fc842e1a30de12876da67a571aa255855e3ae1e63c27f847
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d57c98c31ad7c25f4ad267fe3caa21ae831e986579fef5f2f848c21a7977c0790b461e3372d4cff5e8e89efdb7a0774f06a90542bf0fb4c87baabe8c472ad06
|
7
|
+
data.tar.gz: c99c9d68c24dcccf1bdd164c066466a9c68fa94c7f66dbdc14986dc841e99c0361e32d53a0e2a85226de9c3580ea295254e2c4cb49cd53e974fc28150d3c6e0b
|
@@ -0,0 +1,36 @@
|
|
1
|
+
name: Build
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
fail-fast: false
|
14
|
+
matrix:
|
15
|
+
ruby-version: ['2.5.1', '2.6.2', '2.7.1', '3.0.1']
|
16
|
+
env:
|
17
|
+
DB_DATABASE: workhorse
|
18
|
+
DB_USER: root
|
19
|
+
DB_PASSWORD: 'root'
|
20
|
+
DB_HOST: localhost
|
21
|
+
|
22
|
+
steps:
|
23
|
+
- uses: actions/checkout@v2
|
24
|
+
- name: Set up Ruby
|
25
|
+
uses: ruby/setup-ruby@v1
|
26
|
+
with:
|
27
|
+
ruby-version: ${{ matrix.ruby-version }}
|
28
|
+
bundler-cache: true
|
29
|
+
- name: Startup database
|
30
|
+
run: |
|
31
|
+
sudo /etc/init.d/mysql start
|
32
|
+
mysql -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }} -e 'CREATE DATABASE ${{ env.DB_DATABASE }};'
|
33
|
+
- name: Run rake tests
|
34
|
+
run: bundle exec rake test TESTOPTS='--verbose'
|
35
|
+
- name: Run rubocop
|
36
|
+
run: bundle exec rubocop
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Workhorse Changelog
|
2
2
|
|
3
|
+
## 1.2.7 - 2022-04-07
|
4
|
+
|
5
|
+
* Adapt exit status of shell handler to return with exit code `2` when a worker
|
6
|
+
is in an unexpected status. Previously, this lead to exit code `1` and made it
|
7
|
+
hard to distinguish from fatal errors.
|
8
|
+
|
9
|
+
## 1.2.6 - 2022-01-11
|
10
|
+
|
11
|
+
* Add daemon command `restart-logging`, which sends a `HUP` interrupt to all
|
12
|
+
Workhorse processes which in turn reopen the log files. This is particularly
|
13
|
+
useful to call after log files have been rotated, e.g. using `logrotate`.
|
14
|
+
|
15
|
+
Sitrox reference: #64690.
|
16
|
+
|
17
|
+
## 1.2.5 - 2021-11-01
|
18
|
+
|
19
|
+
* Add config settings for configuring {Workhorse::Jobs::DetectStaleJobsJob}:
|
20
|
+
|
21
|
+
* `config.stale_detection_locked_to_started_threshold`
|
22
|
+
* `config.stale_detection_run_time_threshold`
|
23
|
+
|
3
24
|
## 1.2.4 - 2021-06-08
|
4
25
|
|
5
26
|
* Add `workhorse_db_job` load hook
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](https://github.com/sitrox/workhorse/actions/workflows/ruby.yml)
|
2
2
|
[](https://badge.fury.io/rb/workhorse)
|
3
3
|
|
4
4
|
# Workhorse
|
@@ -107,10 +107,15 @@ method `Workhorse.enqueue_op`:
|
|
107
107
|
Workhorse.enqueue_op Operations::Jobs::CleanUpDatabase, { queue: :maintenance, priority: 2 }, quiet: true
|
108
108
|
```
|
109
109
|
|
110
|
-
|
111
|
-
|
110
|
+
The first argument of the method is the Operation you want to run. Params passed in
|
111
|
+
using the second argument will be used by Workhorse and params passed using the
|
112
|
+
third argument will be used for operation instantiation at job execution, i.e.:
|
112
113
|
|
113
|
-
|
114
|
+
```ruby
|
115
|
+
Workhorse.enqueue_op <Operation Class Name>, { <Workhorse Options> }, { <RailsOps Options> }
|
116
|
+
```
|
117
|
+
|
118
|
+
If you do not want to pass any params to the operation, just omit the third hash:
|
114
119
|
|
115
120
|
```ruby
|
116
121
|
Workhorse.enqueue_op Operations::Jobs::CleanUpDatabase, queue: :maintenance, priority: 2
|
@@ -436,4 +441,4 @@ Please consult the [FAQ](FAQ.md).
|
|
436
441
|
|
437
442
|
## Copyright
|
438
443
|
|
439
|
-
Copyright ©
|
444
|
+
Copyright © 2017 - 2022 Sitrox. See `LICENSE` for further details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.2.
|
1
|
+
1.2.7
|
@@ -26,6 +26,8 @@ module Workhorse
|
|
26
26
|
exit daemon.watch
|
27
27
|
when 'restart'
|
28
28
|
exit daemon.restart
|
29
|
+
when 'restart-logging'
|
30
|
+
exit daemon.restart_logging
|
29
31
|
when 'usage'
|
30
32
|
usage
|
31
33
|
exit 99
|
@@ -68,12 +70,17 @@ Options:
|
|
68
70
|
restart
|
69
71
|
Shortcut for consecutive 'stop' and 'start'.
|
70
72
|
|
73
|
+
restart-logging
|
74
|
+
Re-opens log files, useful e.g. after the log files have been moved or
|
75
|
+
removed by log rotation.
|
76
|
+
|
71
77
|
usage
|
72
78
|
Show this message
|
73
79
|
|
74
80
|
Exit status:
|
75
|
-
0
|
76
|
-
1
|
81
|
+
0 if OK,
|
82
|
+
1 on fatal errors outside of workhorse,
|
83
|
+
2 if at least one worker has an unexpected status,
|
77
84
|
99 on all other errors.
|
78
85
|
USAGE
|
79
86
|
end
|
data/lib/workhorse/daemon.rb
CHANGED
@@ -46,7 +46,7 @@ module Workhorse
|
|
46
46
|
|
47
47
|
if pid_file && pid
|
48
48
|
warn "Worker ##{worker.id} (#{worker.name}): Already started (PID #{pid})" unless quiet
|
49
|
-
code =
|
49
|
+
code = 2
|
50
50
|
elsif pid_file
|
51
51
|
File.delete pid_file
|
52
52
|
puts "Worker ##{worker.id} (#{worker.name}): Starting (stale pid file)" unless quiet
|
@@ -74,7 +74,7 @@ module Workhorse
|
|
74
74
|
puts "Worker (#{worker.name}) ##{worker.id}: Already stopped (stale PID file)"
|
75
75
|
else
|
76
76
|
warn "Worker (#{worker.name}) ##{worker.id}: Already stopped"
|
77
|
-
code =
|
77
|
+
code = 2
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -91,10 +91,10 @@ module Workhorse
|
|
91
91
|
puts "Worker ##{worker.id} (#{worker.name}): Running" unless quiet
|
92
92
|
elsif pid_file
|
93
93
|
warn "Worker ##{worker.id} (#{worker.name}): Not running (stale PID file)" unless quiet
|
94
|
-
code =
|
94
|
+
code = 2
|
95
95
|
else
|
96
96
|
warn "Worker ##{worker.id} (#{worker.name}): Not running" unless quiet
|
97
|
-
code =
|
97
|
+
code = 2
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
@@ -120,6 +120,24 @@ module Workhorse
|
|
120
120
|
return start
|
121
121
|
end
|
122
122
|
|
123
|
+
def restart_logging
|
124
|
+
code = 0
|
125
|
+
|
126
|
+
for_each_worker do |worker|
|
127
|
+
_pid_file, pid = read_pid(worker)
|
128
|
+
|
129
|
+
begin
|
130
|
+
Process.kill 'HUP', pid
|
131
|
+
puts "Worker (#{worker.name}) ##{worker.id}: Sent signal for restart-logging"
|
132
|
+
rescue Errno::ESRCH
|
133
|
+
warn "Worker (#{worker.name}) ##{worker.id}: Could not send signal for restart-logging, process not found"
|
134
|
+
code = 2
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
return code
|
139
|
+
end
|
140
|
+
|
123
141
|
private
|
124
142
|
|
125
143
|
def for_each_worker(&block)
|
@@ -150,6 +168,10 @@ module Workhorse
|
|
150
168
|
File.delete(pid_file)
|
151
169
|
end
|
152
170
|
|
171
|
+
def hup_worker(pid)
|
172
|
+
Process.kill('HUP', pid)
|
173
|
+
end
|
174
|
+
|
153
175
|
def process_name(worker)
|
154
176
|
if defined?(Rails)
|
155
177
|
path = Rails.root
|
@@ -1,18 +1,22 @@
|
|
1
1
|
module Workhorse::Jobs
|
2
|
+
# This job picks up jobs that remained `locked` or `started` (running) for
|
3
|
+
# more than a certain amount of time. If any of these jobs are found, an
|
4
|
+
# exception is thrown (which may cause a notification if you configured
|
5
|
+
# `on_exception` accordingly).
|
6
|
+
#
|
7
|
+
# The thresholds are obtained from the configuration options
|
8
|
+
# {Workhorse.stale_detection_locked_to_started_threshold
|
9
|
+
# config.stale_detection_locked_to_started_threshold} and
|
10
|
+
# {Workhorse.stale_detection_run_time_threshold
|
11
|
+
# config.stale_detection_run_time_threshold}.
|
2
12
|
class DetectStaleJobsJob
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# Set this to 0 to skip this check.
|
8
|
-
# @param run_time_threshold [Integer] The maximum number of seconds
|
9
|
-
# a job is allowed to run before this job throws an exception. Set this to
|
10
|
-
# 0 to skip this check.
|
11
|
-
def initialize(locked_to_started_threshold: 3 * 60, run_time_threshold: 12 * 60)
|
12
|
-
@locked_to_started_threshold = locked_to_started_threshold
|
13
|
-
@run_time_threshold = run_time_threshold
|
13
|
+
# @private
|
14
|
+
def initialize
|
15
|
+
@locked_to_started_threshold = Workhorse.stale_detection_locked_to_started_threshold
|
16
|
+
@run_time_threshold = Workhorse.stale_detection_run_time_threshold
|
14
17
|
end
|
15
18
|
|
19
|
+
# @private
|
16
20
|
def perform
|
17
21
|
messages = []
|
18
22
|
|
data/lib/workhorse/worker.rb
CHANGED
@@ -2,6 +2,7 @@ module Workhorse
|
|
2
2
|
class Worker
|
3
3
|
LOG_LEVELS = %i[fatal error warn info debug].freeze
|
4
4
|
SHUTDOWN_SIGNALS = %w[TERM INT].freeze
|
5
|
+
LOG_REOPEN_SIGNAL = 'HUP'.freeze
|
5
6
|
|
6
7
|
attr_reader :queues
|
7
8
|
attr_reader :state
|
@@ -87,6 +88,7 @@ module Workhorse
|
|
87
88
|
log 'Started up'
|
88
89
|
|
89
90
|
trap_termination if @auto_terminate
|
91
|
+
trap_log_reopen
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
@@ -152,6 +154,18 @@ module Workhorse
|
|
152
154
|
end
|
153
155
|
end
|
154
156
|
|
157
|
+
def trap_log_reopen
|
158
|
+
Signal.trap(LOG_REOPEN_SIGNAL) do
|
159
|
+
Thread.new do
|
160
|
+
logger.reopen
|
161
|
+
|
162
|
+
if defined?(ActiveRecord::Base) && ActiveRecord::Base.logger && ActiveRecord::Base.logger != logger
|
163
|
+
ActiveRecord::Base.logger.reopen
|
164
|
+
end
|
165
|
+
end.join
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
155
169
|
def trap_termination
|
156
170
|
SHUTDOWN_SIGNALS.each do |signal|
|
157
171
|
Signal.trap(signal) do
|
data/lib/workhorse.rb
CHANGED
@@ -45,6 +45,18 @@ module Workhorse
|
|
45
45
|
mattr_accessor :perform_jobs_in_tx
|
46
46
|
self.perform_jobs_in_tx = true
|
47
47
|
|
48
|
+
# This setting is for {Workhorse::Jobs::DetectStaleJobsJob} and specifies the
|
49
|
+
# maximum number of seconds a job is allowed to stay 'locked' before this job
|
50
|
+
# throws an exception. Set this to 0 to skip this check.
|
51
|
+
mattr_accessor :stale_detection_locked_to_started_threshold
|
52
|
+
self.stale_detection_locked_to_started_threshold = 3 * 60
|
53
|
+
|
54
|
+
# This setting is for {Workhorse::Jobs::DetectStaleJobsJob} and specifies the
|
55
|
+
# maximum number of seconds a job is allowed to run before this job throws an
|
56
|
+
# exception. Set this to 0 to skip this check.
|
57
|
+
mattr_accessor :stale_detection_run_time_threshold
|
58
|
+
self.stale_detection_run_time_threshold = 12 * 60
|
59
|
+
|
48
60
|
def self.setup
|
49
61
|
yield self
|
50
62
|
end
|
@@ -73,7 +73,7 @@ class ActiveJob::QueueAdapters::WorkhorseAdapterTest < WorkhorseTest
|
|
73
73
|
work 0.5, polling_interval: 0.1
|
74
74
|
assert_equal 'waiting', Workhorse::DbJob.first.state
|
75
75
|
|
76
|
-
work
|
76
|
+
work 3, polling_interval: 0.1
|
77
77
|
assert_equal 'succeeded', Workhorse::DbJob.first.reload.state
|
78
78
|
end
|
79
79
|
|
data/test/lib/test_helper.rb
CHANGED
data/test/workhorse/pool_test.rb
CHANGED
@@ -61,16 +61,16 @@ class Workhorse::PoolTest < WorkhorseTest
|
|
61
61
|
|
62
62
|
assert_equal 0, on_idle_calls.value
|
63
63
|
|
64
|
-
p.post { sleep 0.2 }
|
65
64
|
p.post { sleep 0.4 }
|
65
|
+
p.post { sleep 0.8 }
|
66
66
|
|
67
67
|
sleep 0.1
|
68
68
|
assert_equal 0, on_idle_calls.value
|
69
69
|
|
70
|
-
sleep 0.
|
70
|
+
sleep 0.6
|
71
71
|
assert_equal 1, on_idle_calls.value
|
72
72
|
|
73
|
-
sleep 0.
|
73
|
+
sleep 0.9
|
74
74
|
assert_equal 2, on_idle_calls.value
|
75
75
|
end
|
76
76
|
end
|
data/workhorse.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: workhorse 1.2.
|
2
|
+
# stub: workhorse 1.2.7 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "workhorse".freeze
|
6
|
-
s.version = "1.2.
|
6
|
+
s.version = "1.2.7"
|
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 = "
|
12
|
-
s.files = [".
|
11
|
+
s.date = "2022-04-07"
|
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/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/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.rubygems_version = "3.0.3".freeze
|
14
14
|
s.summary = "Multi-threaded job backend with database queuing for ruby.".freeze
|
15
15
|
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/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]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: workhorse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sitrox
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -184,10 +184,10 @@ executables: []
|
|
184
184
|
extensions: []
|
185
185
|
extra_rdoc_files: []
|
186
186
|
files:
|
187
|
+
- ".github/workflows/ruby.yml"
|
187
188
|
- ".gitignore"
|
188
189
|
- ".releaser_config"
|
189
190
|
- ".rubocop.yml"
|
190
|
-
- ".travis.yml"
|
191
191
|
- CHANGELOG.md
|
192
192
|
- FAQ.md
|
193
193
|
- Gemfile
|
@@ -245,7 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
245
245
|
- !ruby/object:Gem::Version
|
246
246
|
version: '0'
|
247
247
|
requirements: []
|
248
|
-
rubygems_version: 3.0.3
|
248
|
+
rubygems_version: 3.0.3.1
|
249
249
|
signing_key:
|
250
250
|
specification_version: 4
|
251
251
|
summary: Multi-threaded job backend with database queuing for ruby.
|