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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9b9363247117e0981b8b7304b3ce21d62fc7edf4d5ad3e804d707c0c39ce04e
4
- data.tar.gz: 29a8d3cead2aad95cff3823ab2c88710d97ac26be534aeaba5d3b5570d6ee4a1
3
+ metadata.gz: 31b8b6352a1a32590d8c3d817279a0a7d2cd4c594efe27806acdbea0d1d42062
4
+ data.tar.gz: e68c163ad8f9dbf36ff2dbbd0e4696891b6daf0654b7c343b53f36d7404d8335
5
5
  SHA512:
6
- metadata.gz: d981452366b82c427ab3a8dce44ff100c704e611a39d48e855ef2239a96d67c443d1b7b95f4c87587474a0879430a16eebe1229b89a3fdb3c4414898ed6dd01d
7
- data.tar.gz: 1227833eea17e9202e4d82ea7f9eb36f685e5039a3f63795c35eda88e0eb18de1e0f03d576958177403f3e0e3e2e2842627313fd9362252d5a8eeace29f368f2
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
- worker = Workhorse::Worker.new(pool_size: 5, polling_interval: 10, logger: Rails.logger)
158
- scheduler = Rufus::Scheduler.new
156
+ Workhorse::Daemon::ShellHandler.run do |daemon|
157
+ # Start scheduler process
158
+ daemon.worker 'Scheduler' do
159
+ scheduler = Rufus::Scheduler.new
159
160
 
160
- worker.start
161
+ scheduler.cron '0/10 * * * *' do
162
+ Workhorse.enqueue Workhorse::Jobs::CleanupSucceededJobs.new
163
+ end
161
164
 
162
- scheduler.cron '0/10 * * * *' do
163
- Workhorse.enqueue Workhorse::Jobs::CleanupSucceededJobs.new
164
- end
165
+ Signal.trap 'TERM' do
166
+ scheduler.shutdown
167
+ end
165
168
 
166
- Signal.trap 'TERM' do
167
- scheduler.shutdown
168
- Thread.new do
169
- worker.shutdown
170
- end.join
169
+ scheduler.join
171
170
  end
172
171
 
173
- scheduler.join
174
- worker.wait
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 count: 5 do
237
- # This will be run 5 times, each time in a separate process. Per process, it
238
- # will be able to process 3 jobs concurrently.
239
- Workhorse::Worker.start_and_wait(pool_size: 3, logger: Rails.logger)
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.5.1
1
+ 0.6.0
data/lib/workhorse.rb CHANGED
@@ -4,6 +4,7 @@ require 'active_record'
4
4
  require 'concurrent'
5
5
 
6
6
  require 'workhorse/enqueuer'
7
+ require 'workhorse/scoped_env'
7
8
 
8
9
  module Workhorse
9
10
  # Check if the available Arel version is greater or equal than 7.0.0
@@ -1,17 +1,32 @@
1
1
  module Workhorse
2
2
  class Daemon
3
- def initialize(count: 1, pidfile: nil, quiet: false, &block)
4
- @count = count
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
- @block = block
18
+ @workers = []
19
+
20
+ yield ScopedEnv.new(self, [:worker])
8
21
 
9
- fail 'Count must be an integer > 0.' unless count.is_a?(Integer) && count > 0
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 |worker_id|
26
- pid_file, pid = read_pid(worker_id)
44
+ for_each_worker do |worker|
45
+ pid_file, pid = read_pid(worker)
27
46
 
28
47
  if pid_file && pid
29
- warn "Worker ##{worker_id}: Already started (PID #{pid})"
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 ##{worker_id}: Starting (stale pid file)"
34
- start_worker worker_id
52
+ puts "Worker ##{worker.id} (#{worker.name}): Starting (stale pid file)"
53
+ start_worker worker
35
54
  else
36
- warn "Worker ##{worker_id}: Starting"
37
- start_worker worker_id
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 |worker_id|
48
- pid_file, pid = read_pid(worker_id)
66
+ for_each_worker do |worker|
67
+ pid_file, pid = read_pid(worker)
49
68
 
50
69
  if pid_file && pid
51
- puts "Worker ##{worker_id}: Stopping"
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 ##{worker_id}: Already stopped (stale PID file)"
74
+ puts "Worker (#{worker.name}) ##{worker.id}: Already stopped (stale PID file)"
56
75
  else
57
- warn "Worker ##{worker_id}: Already stopped"
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 |worker_id|
69
- pid_file, pid = read_pid(worker_id)
87
+ for_each_worker do |worker|
88
+ pid_file, pid = read_pid(worker)
70
89
 
71
90
  if pid_file && pid
72
- puts "Worker ##{worker_id}: Running" unless quiet
91
+ puts "Worker ##{worker.id} (#{worker.name}): Running" unless quiet
73
92
  elsif pid_file
74
- warn "Worker ##{worker_id}: Not running (stale PID file)" unless quiet
93
+ warn "Worker ##{worker.id} (#{worker.name}): Not running (stale PID file)" unless quiet
75
94
  code = 1
76
95
  else
77
- warn "Worker ##{worker_id}: Not running" unless quiet
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
- 1.upto(@count, &block)
126
+ @workers.each(&block)
108
127
  end
109
128
 
110
- def start_worker(worker_id)
129
+ def start_worker(worker)
111
130
  pid = fork do
112
- $0 = process_name(worker_id)
113
- @block.call
131
+ $0 = process_name(worker)
132
+ worker.block.call
114
133
  end
115
- IO.write(pid_file_for(worker_id), pid)
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(worker_id)
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 Worker ##{worker_id}: #{path}"
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(worker_id)
154
- @pidfile % worker_id
172
+ def pid_file_for(worker)
173
+ @pidfile % worker.id
155
174
  end
156
175
 
157
- def read_pid(worker_id)
158
- file = pid_file_for(worker_id)
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.5.1 ruby lib
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.5.1"
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-06-27"
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.5.1
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-06-27 00:00:00.000000000 Z
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