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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e00bf821fc0315533d96961d5688b12f6ce20aa70ea84ddb336bbd2a5dac3991
4
- data.tar.gz: 28e9bd8f95d29eb080746ecfa7b9021a4488af1edf9b2023a68f0e98950d9d98
3
+ metadata.gz: 36904c2ff67ab30f876e47515dfd81ccb97715a6e3d563ba93bd59422374d660
4
+ data.tar.gz: 0c9c66eb75727e78fc842e1a30de12876da67a571aa255855e3ae1e63c27f847
5
5
  SHA512:
6
- metadata.gz: c1d9ce641718690cafd39d79e795d487e90aba85c46c46d1a3fbffde99527041160d02831c7da36fbfebca1feff38873e9f6ab31491e6e35aaba9fea5ba06363
7
- data.tar.gz: 92174a5e2ee2882a2ed5f0f46530d773c029e60eb9632cb189e6b7b6bbe3684b3f5e52f35a710aaf013ed6e698ee63962f5b6d9f220cb0fe42ab7305253bec95
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
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 Sitrox
3
+ Copyright (c) 2017 - 2022 Sitrox
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/sitrox/workhorse.svg?branch=master)](https://travis-ci.org/sitrox/workhorse)
1
+ [![Build](https://github.com/sitrox/workhorse/actions/workflows/ruby.yml/badge.svg)](https://github.com/sitrox/workhorse/actions/workflows/ruby.yml)
2
2
  [![Gem Version](https://badge.fury.io/rb/workhorse.svg)](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
- Params passed using the second argument will be used for operation instantiation
111
- at job execution.
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
- If you do not want to pass any params to the operation, just omit the second hash:
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 © 2021 Sitrox. See `LICENSE` for further details.
444
+ Copyright © 2017 - 2022 Sitrox. See `LICENSE` for further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.4
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 if OK,
76
- 1 if at least one worker has an unexpected status,
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
@@ -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 = 1
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 = 1
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 = 1
94
+ code = 2
95
95
  else
96
96
  warn "Worker ##{worker.id} (#{worker.name}): Not running" unless quiet
97
- code = 1
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
- # Instantiates a new stale detection job.
4
- #
5
- # @param locked_to_started_threshold [Integer] The maximum number of seconds
6
- # a job is allowed to stay 'locked' before this job throws an exception.
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
 
@@ -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 1.5, polling_interval: 0.1
76
+ work 3, polling_interval: 0.1
77
77
  assert_equal 'succeeded', Workhorse::DbJob.first.reload.state
78
78
  end
79
79
 
@@ -32,7 +32,7 @@ class WorkhorseTest < ActiveSupport::TestCase
32
32
  end
33
33
 
34
34
  def with_worker(options = {})
35
- w = Workhorse::Worker.new(options)
35
+ w = Workhorse::Worker.new(**options)
36
36
  w.start
37
37
  begin
38
38
  yield(w)
@@ -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.2
70
+ sleep 0.6
71
71
  assert_equal 1, on_idle_calls.value
72
72
 
73
- sleep 0.1
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.4 ruby lib
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.4"
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 = "2021-06-08"
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/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]
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
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: 2021-06-08 00:00:00.000000000 Z
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.
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.5.0
4
- - 2.6.0
5
- services:
6
- - mysql
7
- before_install:
8
- - mysql -e 'CREATE DATABASE workhorse;'
9
- script:
10
- - bundle install
11
- - bundle exec rake test TESTOPTS='--verbose'
12
- - bundle exec rubocop