workhorse 1.2.18 → 1.2.20
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 +12 -0
- data/VERSION +1 -1
- data/lib/workhorse/daemon.rb +8 -0
- data/lib/workhorse/performer.rb +28 -24
- data/lib/workhorse/poller.rb +49 -47
- data/lib/workhorse/pool.rb +6 -4
- data/lib/workhorse/worker.rb +15 -19
- 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: 5779f0370ad5f8c4c99389c7c089d45d68820e9f63703a7886b9b702ba3b9fd3
|
4
|
+
data.tar.gz: fd220b5a403be4a901446b9a1bc55d6acfaf8e6b5302a205d79a20f47951c6cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66a64fc3dc59ed726cb7cdc4774c979bcfafb1246c67e52cac74ff87da9509369fababe6d294fb9943ad8c42a97a41d955277ae07b91e9491f07618a530d6dff
|
7
|
+
data.tar.gz: 1264727996bd00beb9d0f0968e82e34de174ee1529977f55ae87a5a47ec4a70d7c8caa93a3ed78e9816740fb894d748b022a1fe574303f63f9c497a2abf3454b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Workhorse Changelog
|
2
2
|
|
3
|
+
## 1.2.20 - 2024-06-17
|
4
|
+
|
5
|
+
* Fix rails environment check
|
6
|
+
|
7
|
+
Sitrox reference: #125593.
|
8
|
+
|
9
|
+
## 1.2.19 - 2024-05-07
|
10
|
+
|
11
|
+
* Fix further compatibility issues with `ruby < 2.5`
|
12
|
+
|
13
|
+
Sitrox reference: #124538.
|
14
|
+
|
3
15
|
## 1.2.18 - 2024-05-07
|
4
16
|
|
5
17
|
* Fix compatibility with `ruby < 2.5`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.2.
|
1
|
+
1.2.20
|
data/lib/workhorse/daemon.rb
CHANGED
@@ -168,6 +168,8 @@ module Workhorse
|
|
168
168
|
end
|
169
169
|
|
170
170
|
def start_worker(worker)
|
171
|
+
check_rails_env if defined?(Rails)
|
172
|
+
|
171
173
|
pid = fork do
|
172
174
|
$0 = process_name(worker)
|
173
175
|
# Reopen pipes to prevent #107576
|
@@ -244,5 +246,11 @@ module Workhorse
|
|
244
246
|
|
245
247
|
return file, pid, active
|
246
248
|
end
|
249
|
+
|
250
|
+
def check_rails_env
|
251
|
+
unless Rails.env.production?
|
252
|
+
warn 'WARNING: Always run workhorse workers in production environment. Other environments can lead to unexpected behavior.'
|
253
|
+
end
|
254
|
+
end
|
247
255
|
end
|
248
256
|
end
|
data/lib/workhorse/performer.rb
CHANGED
@@ -9,41 +9,45 @@ module Workhorse
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def perform
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
begin
|
13
|
+
fail 'Performer can only run once.' if @started
|
14
|
+
@started = true
|
15
|
+
perform!
|
16
|
+
rescue Exception => e
|
17
|
+
Workhorse.on_exception.call(e)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
21
|
private
|
20
22
|
|
21
23
|
def perform!
|
22
|
-
|
24
|
+
begin
|
25
|
+
Thread.current[:workhorse_current_performer] = self
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
28
|
+
if defined?(Rails) && Rails.respond_to?(:application) && Rails.application && Rails.application.respond_to?(:executor)
|
29
|
+
Rails.application.executor.wrap do
|
30
|
+
perform_wrapped
|
31
|
+
end
|
32
|
+
else
|
27
33
|
perform_wrapped
|
28
34
|
end
|
29
|
-
else
|
30
|
-
perform_wrapped
|
31
35
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
log %(#{e.message}\n#{e.backtrace.join("\n")}), :error
|
36
|
+
rescue Exception => e
|
37
|
+
# ---------------------------------------------------------------
|
38
|
+
# Mark job as failed
|
39
|
+
# ---------------------------------------------------------------
|
40
|
+
log %(#{e.message}\n#{e.backtrace.join("\n")}), :error
|
38
41
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
42
|
+
Workhorse.tx_callback.call do
|
43
|
+
log 'Mark failed', :debug
|
44
|
+
@db_job.mark_failed!(e)
|
45
|
+
end
|
43
46
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
+
fail e
|
48
|
+
ensure
|
49
|
+
Thread.current[:workhorse_current_performer] = nil
|
50
|
+
end
|
47
51
|
end
|
48
52
|
|
49
53
|
def perform_wrapped
|
data/lib/workhorse/poller.rb
CHANGED
@@ -141,60 +141,62 @@ module Workhorse
|
|
141
141
|
end
|
142
142
|
|
143
143
|
def with_global_lock(name: :workhorse, timeout: 2, &_block)
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
144
|
+
begin
|
145
|
+
if @is_oracle
|
146
|
+
result = Workhorse::DbJob.connection.select_all(
|
147
|
+
"SELECT DBMS_LOCK.REQUEST(#{ORACLE_LOCK_HANDLE}, #{ORACLE_LOCK_MODE}, #{timeout}) FROM DUAL"
|
148
|
+
).first.values.last
|
148
149
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
150
|
+
success = result == 0
|
151
|
+
else
|
152
|
+
result = Workhorse::DbJob.connection.select_all(
|
153
|
+
"SELECT GET_LOCK(CONCAT(DATABASE(), '_#{name}'), #{timeout})"
|
154
|
+
).first.values.last
|
155
|
+
success = result == 1
|
156
|
+
end
|
156
157
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
158
|
+
if success
|
159
|
+
@global_lock_fails = 0
|
160
|
+
@max_global_lock_fails_reached = false
|
161
|
+
else
|
162
|
+
@global_lock_fails += 1
|
162
163
|
|
163
|
-
|
164
|
-
|
165
|
-
|
164
|
+
unless @max_global_lock_fails_reached
|
165
|
+
worker.log 'Could not obtain global lock, retrying with next poll.', :warn
|
166
|
+
end
|
166
167
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
168
|
+
if @global_lock_fails > Workhorse.max_global_lock_fails && !@max_global_lock_fails_reached
|
169
|
+
@max_global_lock_fails_reached = true
|
170
|
+
|
171
|
+
worker.log 'Could not obtain global lock, retrying with next poll. ' \
|
172
|
+
'This will be the last such message for this worker until ' \
|
173
|
+
'the issue is resolved.', :warn
|
174
|
+
|
175
|
+
message = "Worker reached maximum number of consecutive times (#{Workhorse.max_global_lock_fails}) " \
|
176
|
+
"where the global lock could no be acquired within the specified timeout (#{timeout}). " \
|
177
|
+
'A worker that obtained this lock may have crashed without ending the database ' \
|
178
|
+
'connection properly. On MySQL, use "show processlist;" to see which connection(s) ' \
|
179
|
+
'is / are holding the lock for a long period of time and consider killing them using ' \
|
180
|
+
"MySQL's \"kill <Id>\" command. This message will be issued only once per worker " \
|
181
|
+
'and may only be re-triggered if the error happens again *after* the lock has ' \
|
182
|
+
'been solved in the meantime.'
|
183
|
+
|
184
|
+
worker.log message
|
185
|
+
exception = StandardError.new(message)
|
186
|
+
Workhorse.on_exception.call(exception)
|
187
|
+
end
|
186
188
|
end
|
187
|
-
end
|
188
189
|
|
189
|
-
|
190
|
+
return unless success
|
190
191
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
192
|
+
yield
|
193
|
+
ensure
|
194
|
+
if success
|
195
|
+
if @is_oracle
|
196
|
+
Workhorse::DbJob.connection.execute("SELECT DBMS_LOCK.RELEASE(#{ORACLE_LOCK_HANDLE}) FROM DUAL")
|
197
|
+
else
|
198
|
+
Workhorse::DbJob.connection.execute("SELECT RELEASE_LOCK(CONCAT(DATABASE(), '_#{name}'))")
|
199
|
+
end
|
198
200
|
end
|
199
201
|
end
|
200
202
|
end
|
data/lib/workhorse/pool.rb
CHANGED
@@ -34,10 +34,12 @@ module Workhorse
|
|
34
34
|
active_threads.increment
|
35
35
|
|
36
36
|
@executor.post do
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
begin
|
38
|
+
yield
|
39
|
+
ensure
|
40
|
+
active_threads.decrement
|
41
|
+
@on_idle.try(:call)
|
42
|
+
end
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
data/lib/workhorse/worker.rb
CHANGED
@@ -67,8 +67,6 @@ module Workhorse
|
|
67
67
|
if instant_repolling
|
68
68
|
@pool.on_idle { @poller.instant_repoll! }
|
69
69
|
end
|
70
|
-
|
71
|
-
check_rails_env if defined?(Rails)
|
72
70
|
end
|
73
71
|
|
74
72
|
def log(text, level = :info)
|
@@ -144,19 +142,23 @@ module Workhorse
|
|
144
142
|
end
|
145
143
|
|
146
144
|
def perform(db_job_id)
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
145
|
+
begin
|
146
|
+
mutex.synchronize do
|
147
|
+
assert_state! :running
|
148
|
+
log "Posting job #{db_job_id} to thread pool"
|
149
|
+
|
150
|
+
@pool.post do
|
151
|
+
begin
|
152
|
+
Workhorse::Performer.new(db_job_id, self).perform
|
153
|
+
rescue Exception => e
|
154
|
+
log %(#{e.message}\n#{e.backtrace.join("\n")}), :error
|
155
|
+
Workhorse.on_exception.call(e)
|
156
|
+
end
|
157
|
+
end
|
156
158
|
end
|
159
|
+
rescue Exception => e
|
160
|
+
Workhorse.on_exception.call(e)
|
157
161
|
end
|
158
|
-
rescue Exception => e
|
159
|
-
Workhorse.on_exception.call(e)
|
160
162
|
end
|
161
163
|
|
162
164
|
private
|
@@ -192,12 +194,6 @@ module Workhorse
|
|
192
194
|
return mem.to_i / 1024
|
193
195
|
end
|
194
196
|
|
195
|
-
def check_rails_env
|
196
|
-
unless Rails.env.production?
|
197
|
-
warn 'WARNING: Always run workhorse workers in production environment. Other environments can lead to unexpected behavior.'
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
197
|
def trap_log_reopen
|
202
198
|
Signal.trap(LOG_REOPEN_SIGNAL) do
|
203
199
|
Thread.new do
|
data/workhorse.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: workhorse 1.2.
|
2
|
+
# stub: workhorse 1.2.20 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.20"
|
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 = "2024-
|
11
|
+
s.date = "2024-06-17"
|
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.rubygems_version = "3.4.6".freeze
|
14
14
|
s.summary = "Multi-threaded job backend with database queuing for ruby.".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.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sitrox
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|