workhorse 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|