workhorse 1.0.0.beta2 → 1.2.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: 70ec4e9fcd51e3f833f4a1f5c340cb64510b2d564fb6f8f17ef090e530ce56e4
4
- data.tar.gz: d0cee1476443206bd7f061e28addaf069489aa2a213e0a24eb36ad8d9e666eb2
3
+ metadata.gz: 0f7aa1675b22da89fef15aadb0ada451a8baf262e2780d973402299c64e653f6
4
+ data.tar.gz: 716b70c048ccb7721ee09baf27fd4eca7b652cbf609de8585af5de1e1b3b2ae4
5
5
  SHA512:
6
- metadata.gz: 802f9ffea56e792143fc0665280f29f127f2b5b71fef9fc39fe1b2f3cf8e119c6785d5ddca7823437c8c17afd83100a8ec43566ccee51369869c922000640d10
7
- data.tar.gz: a0582c12be5b28ab9c36c64c78dce264763e6e423fa3d91dbd18c2385f0681876c81e0fb10d887baf1aaa0a7912cbf97add79555e339631ce82857a15af71516
6
+ metadata.gz: 8e03d563725d51d8b34082f47179999c82e0eb6e493b015222f8c7fc37cae2307cff0a84b7d5311b0c50c86e205fe2d3cb674c0124f8faf01a94241efe607f79
7
+ data.tar.gz: d06e9b188d567a2ac304a513f4e2148af5a9ad1ab94cf509fb7e341d0de891e6533e70eb64662cbbc9c99d7fbfbd7441bf7ef0143890cfd3060e58208aac5767
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.0
4
3
  - 2.5.0
4
+ - 2.6.0
5
5
  services:
6
6
  - mysql
7
7
  before_install:
@@ -1,5 +1,48 @@
1
1
  # Workhorse Changelog
2
2
 
3
+ ## 1.2.0 - 2021-01-27
4
+
5
+ * `Workhorse.enqueue_active_job`
6
+ * Change `perform_at` to a keyword arument
7
+ * Allow passing `:description` and `:queue`
8
+
9
+ Note that when upgrading, change:
10
+
11
+ ```ruby
12
+ # From
13
+ Workhorse.enqueue_active_job MyJob, 5.minutes.from_now
14
+
15
+ # To
16
+ Workhorse.enqueue_active_job MyJob, perform_at: 5.minutes.from_now
17
+ ```
18
+
19
+ ## 1.1.1 - 2021-01-19
20
+
21
+ * Remove deprecation warnings with Ruby 2.7
22
+
23
+ ## 1.1.0 - 2020-12-24
24
+
25
+ * Add `description` column to `DbJob`.
26
+
27
+ If you're upgrading from a previous version, add the `description` column
28
+ to your `DbJob` table, e.g. with such a migration:
29
+
30
+ ```ruby
31
+ class AddDescriptionToWorkhorseDbJobs < ActiveRecord::Migration[6.0]
32
+ def change
33
+ add_column :jobs, :description, :string, after: :perform_at, null: true
34
+ end
35
+ end
36
+ ```
37
+
38
+ ## 1.0.1 - 2020-12-15
39
+
40
+ * Fix handling of empty pid files
41
+
42
+ ## 1.0.0 - 2020-09-21
43
+
44
+ * Stable release, identical to 1.0.0.beta2 but now extensively battle-tested
45
+
3
46
  ## 1.0.0.beta2 - 2020-08-27
4
47
 
5
48
  * Add option `config.silence_poller_exceptions` (default `false`)
data/README.md CHANGED
@@ -81,7 +81,7 @@ GRANT execute ON DBMS_LOCK TO <schema-name>;
81
81
 
82
82
  Workhorse can handle any jobs that support the `perform` method and are
83
83
  serializable. To queue a basic job, use the static method `Workhorse.enqueue`.
84
- You can optionally pass a queue name and a priority.
84
+ You can optionally pass a queue name, a priority and a description (as a string).
85
85
 
86
86
  ```ruby
87
87
  class MyJob
@@ -94,7 +94,7 @@ class MyJob
94
94
  end
95
95
  end
96
96
 
97
- Workhorse.enqueue MyJob.new('John'), queue: :test, priority: 2
97
+ Workhorse.enqueue MyJob.new('John'), queue: :test, priority: 2, description: 'Basic Job'
98
98
  ```
99
99
 
100
100
  ### RailsOps operations
@@ -381,7 +381,7 @@ configuration or else using `self.queue_adapter` in a job class inheriting from
381
381
  Per default, jobs remain in the database, no matter in which state. This can
382
382
  eventually lead to a very large jobs database. You are advised to clean your
383
383
  jobs database on a regular interval. Workhorse provides the job
384
- `Workhose::Jobs::CleanupSucceededJobs` for this purpose that cleans up all
384
+ `Workhorse::Jobs::CleanupSucceededJobs` for this purpose that cleans up all
385
385
  succeeded jobs. You can run this using your scheduler in a specific interval.
386
386
 
387
387
  ## Caveats
@@ -421,4 +421,4 @@ Please consult the [FAQ](FAQ.md).
421
421
 
422
422
  ## Copyright
423
423
 
424
- Copyright © 2020 Sitrox. See `LICENSE` for further details.
424
+ Copyright © 2021 Sitrox. See `LICENSE` for further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.beta2
1
+ 1.2.0
@@ -14,8 +14,8 @@ module ActiveJob
14
14
  Workhorse.enqueue_active_job(job)
15
15
  end
16
16
 
17
- def enqueue_at(job, timestamp) #:nodoc:
18
- Workhorse.enqueue_active_job(job, timestamp)
17
+ def enqueue_at(job, timestamp = Time.now) #:nodoc:
18
+ Workhorse.enqueue_active_job(job, perform_at: timestamp)
19
19
  end
20
20
  end
21
21
  end
@@ -17,6 +17,8 @@ class CreateTableJobs < ActiveRecord::Migration
17
17
  t.integer :priority, null: false
18
18
  t.datetime :perform_at, null: true
19
19
 
20
+ t.string :description, null: true
21
+
20
22
  t.timestamps null: false
21
23
  end
22
24
 
@@ -1,7 +1,8 @@
1
- require 'socket'
2
- require 'active_support/all'
3
1
  require 'active_record'
2
+ require 'active_support/all'
4
3
  require 'concurrent'
4
+ require 'socket'
5
+ require 'uri'
5
6
 
6
7
  require 'workhorse/enqueuer'
7
8
  require 'workhorse/scoped_env'
@@ -177,7 +177,9 @@ module Workhorse
177
177
  file = pid_file_for(worker)
178
178
 
179
179
  if File.exist?(file)
180
- pid = IO.read(file).to_i
180
+ raw_pid = IO.read(file)
181
+ return nil, nil if raw_pid.blank?
182
+ pid = Integer(raw_pid)
181
183
  return file, process?(pid) ? pid : nil
182
184
  else
183
185
  return nil, nil
@@ -1,6 +1,6 @@
1
1
  module Workhorse
2
2
  class Daemon::ShellHandler
3
- def self.run(options = {}, &block)
3
+ def self.run(**options, &block)
4
4
  unless ARGV.count == 1
5
5
  usage
6
6
  exit 99
@@ -10,7 +10,7 @@ module Workhorse
10
10
  lockfile = File.open(lockfile_path, 'a')
11
11
  lockfile.flock(File::LOCK_EX || File::LOCK_NB)
12
12
 
13
- daemon = Workhorse::Daemon.new(options, &block)
13
+ daemon = Workhorse::Daemon.new(**options, &block)
14
14
 
15
15
  begin
16
16
  case ARGV.first
@@ -7,7 +7,7 @@ module Workhorse
7
7
  STATE_FAILED = :failed
8
8
 
9
9
  if respond_to?(:attr_accessible)
10
- attr_accessible :queue, :priority, :perform_at, :handler
10
+ attr_accessible :queue, :priority, :perform_at, :handler, :description
11
11
  end
12
12
 
13
13
  self.table_name = 'jobs'
@@ -1,20 +1,27 @@
1
1
  module Workhorse
2
2
  module Enqueuer
3
3
  # Enqueue any object that is serializable and has a `perform` method
4
- def enqueue(job, queue: nil, priority: 0, perform_at: Time.now)
4
+ def enqueue(job, queue: nil, priority: 0, perform_at: Time.now, description: nil)
5
5
  return DbJob.create!(
6
6
  queue: queue,
7
7
  priority: priority,
8
8
  perform_at: perform_at,
9
+ description: description,
9
10
  handler: Marshal.dump(job)
10
11
  )
11
12
  end
12
13
 
13
14
  # Enqueue an ActiveJob job
14
- def enqueue_active_job(job, perform_at = Time.now)
15
+ def enqueue_active_job(job, perform_at: Time.now, queue: nil, description: nil)
15
16
  wrapper_job = Jobs::RunActiveJob.new(job.serialize)
16
- queue = job.queue_name.blank? ? nil : job.queue_name
17
- db_job = enqueue(wrapper_job, queue: queue, priority: job.priority || 0, perform_at: Time.at(perform_at))
17
+ queue ||= job.queue_name if job.queue_name.present?
18
+ db_job = enqueue(
19
+ wrapper_job,
20
+ queue: queue,
21
+ priority: job.priority || 0,
22
+ perform_at: Time.at(perform_at),
23
+ description: description
24
+ )
18
25
  job.provider_job_id = db_job.id
19
26
  return db_job
20
27
  end
@@ -22,7 +22,7 @@ module Workhorse::Jobs
22
22
  rel = rel.where('locked_at < ?', @locked_to_started_threshold.seconds.ago)
23
23
  ids = rel.pluck(:id)
24
24
 
25
- if ids.size > 0
25
+ unless ids.empty?
26
26
  messages << "Detected #{ids.size} jobs that were locked more than "\
27
27
  "#{@locked_to_started_threshold}s ago and might be stale: #{ids.inspect}."
28
28
  end
@@ -34,7 +34,7 @@ module Workhorse::Jobs
34
34
  rel = rel.where('started_at < ?', @run_time_threshold.seconds.ago)
35
35
  ids = rel.pluck(:id)
36
36
 
37
- if ids.size > 0
37
+ unless ids.empty?
38
38
  messages << "Detected #{ids.size} jobs that are running for longer than "\
39
39
  "#{@run_time_threshold}s ago and might be stale: #{ids.inspect}."
40
40
  end
@@ -3,8 +3,8 @@ module Workhorse
3
3
  MIN_LOCK_TIMEOUT = 0.1 # In seconds
4
4
  MAX_LOCK_TIMEOUT = 1.0 # In seconds
5
5
 
6
- ORACLE_LOCK_MODE = 6 # X_MODE (exclusive)
7
- ORACLE_LOCK_HANDLE = 478564848 # Randomly chosen number
6
+ ORACLE_LOCK_MODE = 6 # X_MODE (exclusive)
7
+ ORACLE_LOCK_HANDLE = 478_564_848 # Randomly chosen number
8
8
 
9
9
  attr_reader :worker
10
10
  attr_reader :table
@@ -72,7 +72,7 @@ module Workhorse
72
72
  end
73
73
  end
74
74
 
75
- def with_global_lock(name: :workhorse, timeout: 2, &block)
75
+ def with_global_lock(name: :workhorse, timeout: 2, &_block)
76
76
  if @is_oracle
77
77
  result = Workhorse::DbJob.connection.select_all(
78
78
  "SELECT DBMS_LOCK.REQUEST(#{ORACLE_LOCK_HANDLE}, #{ORACLE_LOCK_MODE}, #{timeout}) FROM DUAL"
@@ -13,8 +13,8 @@ module Workhorse
13
13
 
14
14
  # Instantiates and starts a new worker with the given arguments and then
15
15
  # waits for its completion (i.e. an interrupt).
16
- def self.start_and_wait(*args)
17
- worker = new(*args)
16
+ def self.start_and_wait(**args)
17
+ worker = new(**args)
18
18
  worker.start
19
19
  worker.wait
20
20
  end
@@ -18,6 +18,8 @@ ActiveRecord::Schema.define do
18
18
  t.integer :priority, null: false
19
19
  t.datetime :perform_at, null: true
20
20
 
21
+ t.string :description, null: true
22
+
21
23
  t.timestamps null: false
22
24
  end
23
25
 
@@ -33,6 +33,15 @@ class Workhorse::EnqueuerTest < WorkhorseTest
33
33
  assert_equal 1, Workhorse::DbJob.first.priority
34
34
  end
35
35
 
36
+ def test_with_description
37
+ assert_equal 0, Workhorse::DbJob.all.count
38
+ Workhorse.enqueue BasicJob.new, description: 'Lorem ipsum'
39
+ assert_equal 1, Workhorse::DbJob.all.count
40
+
41
+ db_job = Workhorse::DbJob.first
42
+ assert_equal 'Lorem ipsum', db_job.description
43
+ end
44
+
36
45
  def test_op
37
46
  Workhorse.enqueue_op DummyRailsOpsOp, { queue: :q1 }, foo: :bar
38
47
 
@@ -48,7 +48,7 @@ class Workhorse::PollerTest < WorkhorseTest
48
48
  assert_equal %w[q1 q2], w.poller.send(:valid_queues)
49
49
  end
50
50
 
51
- def test_valid_queues
51
+ def test_valid_queues_2
52
52
  w = Workhorse::Worker.new(polling_interval: 60)
53
53
 
54
54
  assert_equal [], w.poller.send(:valid_queues)
@@ -148,6 +148,7 @@ class Workhorse::PollerTest < WorkhorseTest
148
148
  assert_equal 25, used_workers
149
149
  end
150
150
 
151
+ # rubocop: disable Style/GlobalVars
151
152
  def test_connection_loss
152
153
  $thread_conn = nil
153
154
 
@@ -174,6 +175,7 @@ class Workhorse::PollerTest < WorkhorseTest
174
175
 
175
176
  assert_equal 1, Workhorse::DbJob.succeeded.count
176
177
  end
178
+ # rubocop: enable Style/GlobalVars
177
179
 
178
180
  private
179
181
 
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: workhorse 1.0.0.beta2 ruby lib
2
+ # stub: workhorse 1.2.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "workhorse".freeze
6
- s.version = "1.0.0.beta2"
6
+ s.version = "1.2.0"
7
7
 
8
- s.required_rubygems_version = Gem::Requirement.new("> 1.3.1".freeze) if s.respond_to? :required_rubygems_version=
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 = "2020-08-27"
11
+ s.date = "2021-01-27"
12
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]
13
13
  s.rubygems_version = "3.0.3".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.0.0.beta2
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sitrox
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-27 00:00:00.000000000 Z
11
+ date: 2021-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -192,8 +192,8 @@ dependencies:
192
192
  - - ">="
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
- description:
196
- email:
195
+ description:
196
+ email:
197
197
  executables: []
198
198
  extensions: []
199
199
  extra_rdoc_files: []
@@ -241,10 +241,10 @@ files:
241
241
  - test/workhorse/pool_test.rb
242
242
  - test/workhorse/worker_test.rb
243
243
  - workhorse.gemspec
244
- homepage:
244
+ homepage:
245
245
  licenses: []
246
246
  metadata: {}
247
- post_install_message:
247
+ post_install_message:
248
248
  rdoc_options: []
249
249
  require_paths:
250
250
  - lib
@@ -255,12 +255,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
255
255
  version: '0'
256
256
  required_rubygems_version: !ruby/object:Gem::Requirement
257
257
  requirements:
258
- - - ">"
258
+ - - ">="
259
259
  - !ruby/object:Gem::Version
260
- version: 1.3.1
260
+ version: '0'
261
261
  requirements: []
262
- rubygems_version: 3.1.2
263
- signing_key:
262
+ rubygems_version: 3.1.4
263
+ signing_key:
264
264
  specification_version: 4
265
265
  summary: Multi-threaded job backend with database queuing for ruby.
266
266
  test_files: