workhorse 0.5.1 → 0.6.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 +4 -4
- data/CHANGELOG.md +31 -0
- data/README.md +26 -19
- data/VERSION +1 -1
- data/lib/workhorse.rb +1 -0
- data/lib/workhorse/daemon.rb +52 -33
- data/lib/workhorse/scoped_env.rb +23 -0
- data/workhorse.gemspec +4 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31b8b6352a1a32590d8c3d817279a0a7d2cd4c594efe27806acdbea0d1d42062
|
4
|
+
data.tar.gz: e68c163ad8f9dbf36ff2dbbd0e4696891b6daf0654b7c343b53f36d7404d8335
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4472fe2d228c7c6fcac24263f1ea33473593971ebaa11bf051131ecf8a810bc162152e5f9cd30aed5c1d9d4b59224f57c0a5b75a4ecb922c3e8bc8303bf3ba48
|
7
|
+
data.tar.gz: cc36d41fe33f5292ae3fbf99c32be84fc0ebd577a43d6e92b7b66009c315bbad4ca650fc0e9d41a37ebb03c3b5b2e82dbfbc9300b3fe889ec30929f7768015b6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,36 @@
|
|
1
1
|
# Workhorse Change log
|
2
2
|
|
3
|
+
## 0.6.0 - 2918-07-03
|
4
|
+
|
5
|
+
* Adapt {Workhorse::Daemon} to support a specific block for each worker. This
|
6
|
+
allows, for example, to run a scheduler like Rufus in a separate worker
|
7
|
+
process.
|
8
|
+
|
9
|
+
If you're using the daemon class, you will need to restructure your workhorse
|
10
|
+
starting script.
|
11
|
+
|
12
|
+
Since there is no `count` attribute anymore, transfer this:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
Workhorse::Daemon::ShellHandler.run count: 5 do
|
16
|
+
# ... worker code
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
into this:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
Workhorse::Daemon::ShellHandler.run do |daemon|
|
24
|
+
5.times do
|
25
|
+
daemon.worker do
|
26
|
+
# ... worker code
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
See readme for more information.
|
33
|
+
|
3
34
|
## 0.5.1 - 2019-06-27
|
4
35
|
|
5
36
|
* Add daemon command `kill`
|
data/README.md
CHANGED
@@ -153,25 +153,28 @@ achieving regular execution:
|
|
153
153
|
|
154
154
|
require './config/environment'
|
155
155
|
|
156
|
-
Workhorse::Daemon::ShellHandler.run do
|
157
|
-
|
158
|
-
|
156
|
+
Workhorse::Daemon::ShellHandler.run do |daemon|
|
157
|
+
# Start scheduler process
|
158
|
+
daemon.worker 'Scheduler' do
|
159
|
+
scheduler = Rufus::Scheduler.new
|
159
160
|
|
160
|
-
|
161
|
+
scheduler.cron '0/10 * * * *' do
|
162
|
+
Workhorse.enqueue Workhorse::Jobs::CleanupSucceededJobs.new
|
163
|
+
end
|
161
164
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
+
Signal.trap 'TERM' do
|
166
|
+
scheduler.shutdown
|
167
|
+
end
|
165
168
|
|
166
|
-
|
167
|
-
scheduler.shutdown
|
168
|
-
Thread.new do
|
169
|
-
worker.shutdown
|
170
|
-
end.join
|
169
|
+
scheduler.join
|
171
170
|
end
|
172
171
|
|
173
|
-
|
174
|
-
|
172
|
+
# Start 5 worker processes with 3 threads each
|
173
|
+
5.times do
|
174
|
+
daemon.worker do
|
175
|
+
Workhorse::Worker.new(pool_size: 3, polling_interval: 10, logger: Rails.logger)
|
176
|
+
end
|
177
|
+
end
|
175
178
|
end
|
176
179
|
```
|
177
180
|
|
@@ -224,7 +227,7 @@ For this case, the workhorse install routine automatically creates the file
|
|
224
227
|
The script can be called as follows:
|
225
228
|
|
226
229
|
```bash
|
227
|
-
RAILS_ENV=production bundle exec bin/workhorse.rb start|stop|status|watch|restart|usage
|
230
|
+
RAILS_ENV=production bundle exec bin/workhorse.rb start|stop|kill|status|watch|restart|usage
|
228
231
|
```
|
229
232
|
|
230
233
|
#### Background and customization
|
@@ -233,10 +236,14 @@ Within the shell handler, you can instantiate, configure, and start a worker as
|
|
233
236
|
described under [Start workers manually](#start-workers-manually):
|
234
237
|
|
235
238
|
```ruby
|
236
|
-
Workhorse::Daemon::ShellHandler.run
|
237
|
-
|
238
|
-
|
239
|
-
|
239
|
+
Workhorse::Daemon::ShellHandler.run do |daemon|
|
240
|
+
5.times do
|
241
|
+
daemon.worker do
|
242
|
+
# This will be run 5 times, each time in a separate process. Per process, it
|
243
|
+
# will be able to process 3 jobs concurrently.
|
244
|
+
Workhorse::Worker.start_and_wait(pool_size: 3, logger: Rails.logger)
|
245
|
+
end
|
246
|
+
end
|
240
247
|
end
|
241
248
|
```
|
242
249
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/lib/workhorse.rb
CHANGED
data/lib/workhorse/daemon.rb
CHANGED
@@ -1,17 +1,32 @@
|
|
1
1
|
module Workhorse
|
2
2
|
class Daemon
|
3
|
-
|
4
|
-
|
3
|
+
class Worker
|
4
|
+
attr_reader :id
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :block
|
7
|
+
|
8
|
+
def initialize(id, name, &block)
|
9
|
+
@id = id
|
10
|
+
@name = name
|
11
|
+
@block = block
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(pidfile: nil, quiet: false, &block)
|
5
16
|
@pidfile = pidfile
|
6
17
|
@quiet = quiet
|
7
|
-
@
|
18
|
+
@workers = []
|
19
|
+
|
20
|
+
yield ScopedEnv.new(self, [:worker])
|
8
21
|
|
9
|
-
|
22
|
+
@count = @workers.count
|
23
|
+
|
24
|
+
fail 'No workers are defined.' if @count == 1
|
10
25
|
|
11
26
|
FileUtils.mkdir_p('tmp/pids')
|
12
27
|
|
13
28
|
if @pidfile.nil?
|
14
|
-
@pidfile = count > 1 ? 'tmp/pids/workhorse.%i.pid' : 'tmp/pids/workhorse.pid'
|
29
|
+
@pidfile = @count > 1 ? 'tmp/pids/workhorse.%i.pid' : 'tmp/pids/workhorse.pid'
|
15
30
|
elsif @count > 1 && !@pidfile.include?('%s')
|
16
31
|
fail 'Pidfile must include placeholder "%s" for worker id when specifying a count > 1.'
|
17
32
|
elsif @count == 0 && @pidfile.include?('%s')
|
@@ -19,22 +34,26 @@ module Workhorse
|
|
19
34
|
end
|
20
35
|
end
|
21
36
|
|
37
|
+
def worker(name = 'Job Worker', &block)
|
38
|
+
@workers << Worker.new(@workers.size + 1, name, &block)
|
39
|
+
end
|
40
|
+
|
22
41
|
def start
|
23
42
|
code = 0
|
24
43
|
|
25
|
-
for_each_worker do |
|
26
|
-
pid_file, pid = read_pid(
|
44
|
+
for_each_worker do |worker|
|
45
|
+
pid_file, pid = read_pid(worker)
|
27
46
|
|
28
47
|
if pid_file && pid
|
29
|
-
warn "Worker ##{
|
48
|
+
warn "Worker ##{worker.id} (#{worker.name}): Already started (PID #{pid})"
|
30
49
|
code = 1
|
31
50
|
elsif pid_file
|
32
51
|
File.delete pid_file
|
33
|
-
puts "Worker ##{
|
34
|
-
start_worker
|
52
|
+
puts "Worker ##{worker.id} (#{worker.name}): Starting (stale pid file)"
|
53
|
+
start_worker worker
|
35
54
|
else
|
36
|
-
warn "Worker ##{
|
37
|
-
start_worker
|
55
|
+
warn "Worker ##{worker.id} (#{worker.name}): Starting"
|
56
|
+
start_worker worker
|
38
57
|
end
|
39
58
|
end
|
40
59
|
|
@@ -44,17 +63,17 @@ module Workhorse
|
|
44
63
|
def stop(kill = false)
|
45
64
|
code = 0
|
46
65
|
|
47
|
-
for_each_worker do |
|
48
|
-
pid_file, pid = read_pid(
|
66
|
+
for_each_worker do |worker|
|
67
|
+
pid_file, pid = read_pid(worker)
|
49
68
|
|
50
69
|
if pid_file && pid
|
51
|
-
puts "Worker ##{
|
70
|
+
puts "Worker (#{worker.name}) ##{worker.id}: Stopping"
|
52
71
|
stop_worker pid_file, pid, kill
|
53
72
|
elsif pid_file
|
54
73
|
File.delete pid_file
|
55
|
-
puts "Worker ##{
|
74
|
+
puts "Worker (#{worker.name}) ##{worker.id}: Already stopped (stale PID file)"
|
56
75
|
else
|
57
|
-
warn "Worker ##{
|
76
|
+
warn "Worker (#{worker.name}) ##{worker.id}: Already stopped"
|
58
77
|
code = 1
|
59
78
|
end
|
60
79
|
end
|
@@ -65,16 +84,16 @@ module Workhorse
|
|
65
84
|
def status(quiet: false)
|
66
85
|
code = 0
|
67
86
|
|
68
|
-
for_each_worker do |
|
69
|
-
pid_file, pid = read_pid(
|
87
|
+
for_each_worker do |worker|
|
88
|
+
pid_file, pid = read_pid(worker)
|
70
89
|
|
71
90
|
if pid_file && pid
|
72
|
-
puts "Worker ##{
|
91
|
+
puts "Worker ##{worker.id} (#{worker.name}): Running" unless quiet
|
73
92
|
elsif pid_file
|
74
|
-
warn "Worker ##{
|
93
|
+
warn "Worker ##{worker.id} (#{worker.name}): Not running (stale PID file)" unless quiet
|
75
94
|
code = 1
|
76
95
|
else
|
77
|
-
warn "Worker ##{
|
96
|
+
warn "Worker ##{worker.id} (#{worker.name}): Not running" unless quiet
|
78
97
|
code = 1
|
79
98
|
end
|
80
99
|
end
|
@@ -104,15 +123,15 @@ module Workhorse
|
|
104
123
|
private
|
105
124
|
|
106
125
|
def for_each_worker(&block)
|
107
|
-
|
126
|
+
@workers.each(&block)
|
108
127
|
end
|
109
128
|
|
110
|
-
def start_worker(
|
129
|
+
def start_worker(worker)
|
111
130
|
pid = fork do
|
112
|
-
$0 = process_name(
|
113
|
-
|
131
|
+
$0 = process_name(worker)
|
132
|
+
worker.block.call
|
114
133
|
end
|
115
|
-
IO.write(pid_file_for(
|
134
|
+
IO.write(pid_file_for(worker), pid)
|
116
135
|
end
|
117
136
|
|
118
137
|
def stop_worker(pid_file, pid, kill = false)
|
@@ -131,14 +150,14 @@ module Workhorse
|
|
131
150
|
File.delete(pid_file)
|
132
151
|
end
|
133
152
|
|
134
|
-
def process_name(
|
153
|
+
def process_name(worker)
|
135
154
|
if defined?(Rails)
|
136
155
|
path = Rails.root
|
137
156
|
else
|
138
157
|
path = $PROGRAM_NAME
|
139
158
|
end
|
140
159
|
|
141
|
-
return "Workhorse
|
160
|
+
return "Workhorse #{worker.name} ##{worker.id}: #{path}"
|
142
161
|
end
|
143
162
|
|
144
163
|
def process?(pid)
|
@@ -150,12 +169,12 @@ module Workhorse
|
|
150
169
|
end
|
151
170
|
end
|
152
171
|
|
153
|
-
def pid_file_for(
|
154
|
-
@pidfile %
|
172
|
+
def pid_file_for(worker)
|
173
|
+
@pidfile % worker.id
|
155
174
|
end
|
156
175
|
|
157
|
-
def read_pid(
|
158
|
-
file = pid_file_for(
|
176
|
+
def read_pid(worker)
|
177
|
+
file = pid_file_for(worker)
|
159
178
|
|
160
179
|
if File.exist?(file)
|
161
180
|
pid = IO.read(file).to_i
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Workhorse
|
2
|
+
class ScopedEnv
|
3
|
+
def initialize(delegation_object, methods, backup_binding = nil)
|
4
|
+
@delegation_object = delegation_object
|
5
|
+
@methods = methods
|
6
|
+
@backup_binding = backup_binding
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(symbol, *args, &block)
|
10
|
+
if @methods.include?(symbol)
|
11
|
+
@delegation_object.send(symbol, *args, &block)
|
12
|
+
elsif @backup_binding&.respond_to?(symbol)
|
13
|
+
@backup_binding.send(symbol, *args, &block)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to_missing?(symbol, include_private = false)
|
20
|
+
@methods.include?(symbol) || super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/workhorse.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: workhorse 0.
|
2
|
+
# stub: workhorse 0.6.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "workhorse".freeze
|
6
|
-
s.version = "0.
|
6
|
+
s.version = "0.6.0"
|
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 = "2019-
|
12
|
-
s.files = [".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, ".travis.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/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/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]
|
11
|
+
s.date = "2019-07-03"
|
12
|
+
s.files = [".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, ".travis.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/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: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sitrox
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -213,6 +213,7 @@ files:
|
|
213
213
|
- lib/workhorse/performer.rb
|
214
214
|
- lib/workhorse/poller.rb
|
215
215
|
- lib/workhorse/pool.rb
|
216
|
+
- lib/workhorse/scoped_env.rb
|
216
217
|
- lib/workhorse/worker.rb
|
217
218
|
- test/active_job/queue_adapters/workhorse_adapter_test.rb
|
218
219
|
- test/lib/db_schema.rb
|