good_job 1.3.0 → 1.3.1

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: 17fac9485f08bf55c8d2b2fbbc6e85efde95202d759d6155a4b23bf0755236ce
4
- data.tar.gz: 562115863243ac98e3fd0cca7c04ad9f57a80f932682d7161e43336b521ea62d
3
+ metadata.gz: ce89780b94c2a1f01cff7b85b3bdb066988a50c1b55ecef909d69ed0dbce5b00
4
+ data.tar.gz: e68b2a0b1283e79d30d8dd49e13a8f01fea53e7cf99d60aa9ab243826177838a
5
5
  SHA512:
6
- metadata.gz: a06ee5d2bea077e7b612f6d44aa30666d52517849e5345d8882a9f21653513be2386e577dbbab8ad41897aeb48d14885cbfe8cd51784c96da300aee7233a5190
7
- data.tar.gz: 7c366b21a4f28d66ce8d59d22fa56a081a63c181ee0b35ddd7965422c7c758f020bc7fba42aa34e61ec8abb17e9dcc5a9d0cb3b15f2d1c03d7153d83d7fbffdd
6
+ metadata.gz: 1332dd583ab8d0d1e359b85c0f03d082a2407f0ef825d419aae4986e003a18a9adfce9e253aaa5a386497b1a0fc941f732968caac3a813c78f079c23fae2bd72
7
+ data.tar.gz: 1650338a713a12387b15241eb5d8808ac9fbf43fa780645c1886612ba0590ca392f2dbd93e6c8a82e5483ddb3e3ba60d0c4e04695c6155ae3993d82af42bbef7
@@ -1,12 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.3.1](https://github.com/bensheldon/good_job/tree/v1.3.1) (2020-11-01)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.0...v1.3.1)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Extract polling from scheduler into Polling object [\#128](https://github.com/bensheldon/good_job/issues/128)
10
+ - Format serialized params to ease reading [\#170](https://github.com/bensheldon/good_job/pull/170) ([morgoth](https://github.com/morgoth))
11
+
12
+ **Fixed bugs:**
13
+
14
+ - Don't disconnect a nil activerecord connection [\#161](https://github.com/bensheldon/good_job/pull/161) ([bensheldon](https://github.com/bensheldon))
15
+
16
+ **Closed issues:**
17
+
18
+ - Propose addition of GoodJob to queue-shootout benchmarks [\#40](https://github.com/bensheldon/good_job/issues/40)
19
+
20
+ **Merged pull requests:**
21
+
22
+ - Ensure Rails is a development dependency [\#169](https://github.com/bensheldon/good_job/pull/169) ([bensheldon](https://github.com/bensheldon))
23
+ - Fix Ruby 2.7 GH action by setting default bundler explicitly [\#166](https://github.com/bensheldon/good_job/pull/166) ([bensheldon](https://github.com/bensheldon))
24
+ - Cache ruby version explicitly in Github Action [\#165](https://github.com/bensheldon/good_job/pull/165) ([bensheldon](https://github.com/bensheldon))
25
+ - Update development dependencies, rubocop [\#164](https://github.com/bensheldon/good_job/pull/164) ([bensheldon](https://github.com/bensheldon))
26
+ - Fix intended constant hierarchy of GoodJob::Scheduler::ThreadPoolExecutor [\#158](https://github.com/bensheldon/good_job/pull/158) ([bensheldon](https://github.com/bensheldon))
27
+ - Add bin/test\_app executable for Rails debugging [\#157](https://github.com/bensheldon/good_job/pull/157) ([bensheldon](https://github.com/bensheldon))
28
+ - Extract Scheduler polling behavior to its own object [\#152](https://github.com/bensheldon/good_job/pull/152) ([bensheldon](https://github.com/bensheldon))
29
+
3
30
  ## [v1.3.0](https://github.com/bensheldon/good_job/tree/v1.3.0) (2020-10-03)
4
31
 
5
32
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.2.6...v1.3.0)
6
33
 
7
- **Merged pull requests:**
34
+ **Implemented enhancements:**
8
35
 
9
36
  - Lengthen default poll interval from 1 to 5 seconds [\#156](https://github.com/bensheldon/good_job/pull/156) ([bensheldon](https://github.com/bensheldon))
37
+
38
+ **Merged pull requests:**
39
+
10
40
  - Rename reperform\_jobs\_on\_standard\_error to retry\_on\_unhandled\_error [\#154](https://github.com/bensheldon/good_job/pull/154) ([morgoth](https://github.com/morgoth))
11
41
 
12
42
  ## [v1.2.6](https://github.com/bensheldon/good_job/tree/v1.2.6) (2020-09-29)
@@ -4,7 +4,7 @@ module GoodJob
4
4
  @jobs = GoodJob::Job.display_all(after_scheduled_at: params[:after_scheduled_at], after_id: params[:after_id])
5
5
  .limit(params.fetch(:limit, 10))
6
6
 
7
- job_data = GoodJob::Job.connection.exec_query Arel.sql(<<~SQL)
7
+ job_data = GoodJob::Job.connection.exec_query Arel.sql(<<~SQL.squish)
8
8
  SELECT *
9
9
  FROM generate_series(
10
10
  date_trunc('hour', NOW() - '1 day'::interval),
@@ -6,8 +6,8 @@
6
6
  <th>Job Class</th>
7
7
  <th>Queue</th>
8
8
  <th>Scheduled At</th>
9
- <th>ActiveJob Params</th>
10
9
  <th>Error</th>
10
+ <th>ActiveJob Params</th>
11
11
  </thead>
12
12
  <tbody>
13
13
  <% jobs.each do |job| %>
@@ -17,8 +17,8 @@
17
17
  <td><%= job.serialized_params['job_class'] %></td>
18
18
  <td><%= job.queue_name %></td>
19
19
  <td><%= job.scheduled_at || job.created_at %></td>
20
- <td><%= job.serialized_params %></td>
21
20
  <td><%= job.error %></td>
21
+ <td><pre><%= JSON.pretty_generate(job.serialized_params) %></pre></td>
22
22
  </tr>
23
23
  <% end %>
24
24
  </tbody>
@@ -43,8 +43,10 @@ module GoodJob
43
43
 
44
44
  if @execution_mode == :async # rubocop:disable Style/GuardClause
45
45
  @notifier = notifier || GoodJob::Notifier.new
46
+ @poller = GoodJob::Poller.new(poll_interval: configuration.poll_interval)
46
47
  @scheduler = scheduler || GoodJob::Scheduler.from_configuration(configuration)
47
48
  @notifier.recipients << [@scheduler, :create_thread]
49
+ @poller.recipients << [@scheduler, :create_thread]
48
50
  end
49
51
  end
50
52
 
@@ -88,6 +90,7 @@ module GoodJob
88
90
  # @return [void]
89
91
  def shutdown(wait: true)
90
92
  @notifier&.shutdown(wait: wait)
93
+ @poller&.shutdown(wait: wait)
91
94
  @scheduler&.shutdown(wait: wait)
92
95
  end
93
96
 
@@ -45,11 +45,13 @@ module GoodJob
45
45
  desc: "Interval between polls for available jobs in seconds (env var: GOOD_JOB_POLL_INTERVAL, default: 5)"
46
46
  def start
47
47
  set_up_application!
48
+ configuration = GoodJob::Configuration.new(options)
48
49
 
49
50
  notifier = GoodJob::Notifier.new
50
- configuration = GoodJob::Configuration.new(options)
51
+ poller = GoodJob::Poller.new(poll_interval: configuration.poll_interval)
51
52
  scheduler = GoodJob::Scheduler.from_configuration(configuration)
52
53
  notifier.recipients << [scheduler, :create_thread]
54
+ poller.recipients << [scheduler, :create_thread]
53
55
 
54
56
  @stop_good_job_executable = false
55
57
  %w[INT TERM].each do |signal|
@@ -62,6 +64,7 @@ module GoodJob
62
64
  end
63
65
 
64
66
  notifier.shutdown
67
+ poller.shutdown
65
68
  scheduler.shutdown
66
69
  end
67
70
 
@@ -56,7 +56,7 @@ module GoodJob
56
56
  # @example Get the records that have a session awaiting a lock:
57
57
  # MyLockableRecord.joins_advisory_locks.where("pg_locks.granted = ?", false)
58
58
  scope :joins_advisory_locks, (lambda do
59
- join_sql = <<~SQL
59
+ join_sql = <<~SQL.squish
60
60
  LEFT JOIN pg_locks ON pg_locks.locktype = 'advisory'
61
61
  AND pg_locks.objsubid = 1
62
62
  AND pg_locks.classid = ('x' || substr(md5(:table_name || #{quoted_table_name}.#{quoted_primary_key}::text), 1, 16))::bit(32)::int
@@ -140,10 +140,10 @@ module GoodJob
140
140
  # all remaining locks).
141
141
  # @return [Boolean] whether the lock was acquired.
142
142
  def advisory_lock
143
- where_sql = <<~SQL
143
+ where_sql = <<~SQL.squish
144
144
  pg_try_advisory_lock(('x' || substr(md5(:table_name || :id::text), 1, 16))::bit(64)::bigint)
145
145
  SQL
146
- self.class.unscoped.where(where_sql, { table_name: self.class.table_name, id: send(self.class.primary_key) }).exists?
146
+ self.class.unscoped.exists?([where_sql, { table_name: self.class.table_name, id: send(self.class.primary_key) }])
147
147
  end
148
148
 
149
149
  # Releases an advisory lock on this record if it is locked by this database
@@ -151,10 +151,10 @@ module GoodJob
151
151
  # {#advisory_unlock} and {#advisory_lock} the same number of times.
152
152
  # @return [Boolean] whether the lock was released.
153
153
  def advisory_unlock
154
- where_sql = <<~SQL
154
+ where_sql = <<~SQL.squish
155
155
  pg_advisory_unlock(('x' || substr(md5(:table_name || :id::text), 1, 16))::bit(64)::bigint)
156
156
  SQL
157
- self.class.unscoped.where(where_sql, { table_name: self.class.table_name, id: send(self.class.primary_key) }).exists?
157
+ self.class.unscoped.exists?([where_sql, { table_name: self.class.table_name, id: send(self.class.primary_key) }])
158
158
  end
159
159
 
160
160
  # Acquires an advisory lock on this record or raises
@@ -191,13 +191,13 @@ module GoodJob
191
191
  # Tests whether this record has an advisory lock on it.
192
192
  # @return [Boolean]
193
193
  def advisory_locked?
194
- self.class.unscoped.advisory_locked.where(id: send(self.class.primary_key)).exists?
194
+ self.class.unscoped.advisory_locked.exists?(id: send(self.class.primary_key))
195
195
  end
196
196
 
197
197
  # Tests whether this record is locked by the current database session.
198
198
  # @return [Boolean]
199
199
  def owns_advisory_lock?
200
- self.class.unscoped.owns_advisory_locked.where(id: send(self.class.primary_key)).exists?
200
+ self.class.unscoped.owns_advisory_locked.exists?(id: send(self.class.primary_key))
201
201
  end
202
202
 
203
203
  # Releases all advisory locks on the record that are held by the current
@@ -45,14 +45,13 @@ module GoodJob
45
45
  end
46
46
 
47
47
  # @macro notification_responder
48
- def scheduler_create_pools(event)
48
+ def scheduler_create_pool(event)
49
49
  max_threads = event.payload[:max_threads]
50
- poll_interval = event.payload[:poll_interval]
51
50
  performer_name = event.payload[:performer_name]
52
51
  process_id = event.payload[:process_id]
53
52
 
54
53
  info(tags: [process_id]) do
55
- "GoodJob started scheduler with queues=#{performer_name} max_threads=#{max_threads} poll_interval=#{poll_interval}."
54
+ "GoodJob started scheduler with queues=#{performer_name} max_threads=#{max_threads}."
56
55
  end
57
56
  end
58
57
 
@@ -166,12 +165,12 @@ module GoodJob
166
165
  # @return [Logger]
167
166
  def logger
168
167
  @_logger ||= begin
169
- logger = Logger.new(StringIO.new)
170
- loggers.each do |each_logger|
171
- logger.extend(ActiveSupport::Logger.broadcast(each_logger))
172
- end
173
- logger
174
- end
168
+ logger = Logger.new(StringIO.new)
169
+ loggers.each do |each_logger|
170
+ logger.extend(ActiveSupport::Logger.broadcast(each_logger))
171
+ end
172
+ logger
173
+ end
175
174
  end
176
175
 
177
176
  # Reset {LogSubscriber.logger} and force it to rebuild a new shortcut to
@@ -192,11 +191,12 @@ module GoodJob
192
191
  # @return [void]
193
192
  def tag_logger(*tags, &block)
194
193
  tags = tags.dup.unshift("GoodJob").compact
194
+ good_job_tag = ["ActiveJob"].freeze
195
195
 
196
196
  self.class.loggers.inject(block) do |inner, each_logger|
197
197
  if each_logger.respond_to?(:tagged)
198
198
  tags_for_logger = if each_logger.formatter.current_tags.include?("ActiveJob")
199
- ["ActiveJob"] + tags
199
+ good_job_tag + tags
200
200
  else
201
201
  tags
202
202
  end
@@ -34,7 +34,7 @@ module GoodJob # :nodoc:
34
34
  # @param message [#to_json]
35
35
  def self.notify(message)
36
36
  connection = ActiveRecord::Base.connection
37
- connection.exec_query <<~SQL
37
+ connection.exec_query <<~SQL.squish
38
38
  NOTIFY #{CHANNEL}, #{connection.quote(message.to_json)}
39
39
  SQL
40
40
  end
@@ -75,7 +75,7 @@ module GoodJob # :nodoc:
75
75
  # If +wait+ is +true+, the notifier will wait for background thread to shutdown.
76
76
  # If +wait+ is +false+, this method will return immediately even though threads may still be running.
77
77
  # Use {#shutdown?} to determine whether threads have stopped.
78
- # @param wait [Boolean] Wait for actively executing jobs to finish
78
+ # @param wait [Boolean] Wait for actively executing threads to finish
79
79
  # @return [void]
80
80
  def shutdown(wait: true)
81
81
  return unless @pool.running?
@@ -147,7 +147,7 @@ module GoodJob # :nodoc:
147
147
  pg_conn.exec("SET application_name = #{pg_conn.escape_identifier(self.class.name)}")
148
148
  yield pg_conn
149
149
  ensure
150
- ar_conn.disconnect!
150
+ ar_conn&.disconnect!
151
151
  end
152
152
  end
153
153
  end
@@ -0,0 +1,94 @@
1
+ require 'concurrent/atomic/atomic_boolean'
2
+
3
+ module GoodJob # :nodoc:
4
+ #
5
+ # Pollers regularly wake up execution threads to check for new work.
6
+ #
7
+ class Poller
8
+ # Defaults for instance of Concurrent::TimerTask.
9
+ # The timer controls how and when sleeping threads check for new work.
10
+ DEFAULT_TIMER_OPTIONS = {
11
+ execution_interval: Configuration::DEFAULT_POLL_INTERVAL,
12
+ timeout_interval: 1,
13
+ run_now: true,
14
+ }.freeze
15
+
16
+ # @!attribute [r] instances
17
+ # @!scope class
18
+ # List of all instantiated Pollers in the current process.
19
+ # @return [array<GoodJob:Poller>]
20
+ cattr_reader :instances, default: [], instance_reader: false
21
+
22
+ def self.from_configuration(configuration)
23
+ GoodJob::Poller.new(poll_interval: configuration.poll_interval)
24
+ end
25
+
26
+ # List of recipients that will receive notifications.
27
+ # @return [Array<#call, Array(Object, Symbol)>]
28
+ attr_reader :recipients
29
+
30
+ # @param recipients [Array<#call, Array(Object, Symbol)>]
31
+ # @param poll_interval [Hash] number of seconds between polls
32
+ def initialize(*recipients, poll_interval: nil)
33
+ @recipients = Concurrent::Array.new(recipients)
34
+
35
+ @timer_options = DEFAULT_TIMER_OPTIONS.dup
36
+ @timer_options[:execution_interval] = poll_interval if poll_interval.present?
37
+
38
+ self.class.instances << self
39
+
40
+ create_pool
41
+ end
42
+
43
+ # Shut down the poller.
44
+ # If +wait+ is +true+, the poller will wait for background thread to shutdown.
45
+ # If +wait+ is +false+, this method will return immediately even though threads may still be running.
46
+ # Use {#shutdown?} to determine whether threads have stopped.
47
+ # @param wait [Boolean] Wait for actively executing threads to finish
48
+ # @return [void]
49
+ def shutdown(wait: true)
50
+ return unless @timer&.running?
51
+
52
+ @timer.shutdown
53
+ @timer.wait_for_termination if wait
54
+ end
55
+
56
+ # Tests whether the poller is shutdown.
57
+ # @return [true, false, nil]
58
+ def shutdown?
59
+ !@timer&.running?
60
+ end
61
+
62
+ # Restart the poller.
63
+ # When shutdown, start; or shutdown and start.
64
+ # @param wait [Boolean] Wait for background thread to finish
65
+ # @return [void]
66
+ def restart(wait: true)
67
+ shutdown(wait: wait)
68
+ create_pool
69
+ end
70
+
71
+ # Invoked on completion of TimerTask task.
72
+ # @!visibility private
73
+ # @return [void]
74
+ def timer_observer(time, executed_task, thread_error)
75
+ GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
76
+ instrument("finished_timer_task", { result: executed_task, error: thread_error, time: time })
77
+ end
78
+
79
+ private
80
+
81
+ def create_pool
82
+ return if @timer_options[:execution_interval] <= 0
83
+
84
+ @timer = Concurrent::TimerTask.new(@timer_options) do
85
+ recipients.each do |recipient|
86
+ target, method_name = recipient.is_a?(Array) ? recipient : [recipient, :call]
87
+ target.send(method_name)
88
+ end
89
+ end
90
+ @timer.add_observer(self, :timer_observer)
91
+ @timer.execute
92
+ end
93
+ end
94
+ end
@@ -26,14 +26,6 @@ module GoodJob # :nodoc:
26
26
  fallback_policy: :discard,
27
27
  }.freeze
28
28
 
29
- # Defaults for instance of Concurrent::TimerTask.
30
- # The timer controls how and when sleeping threads check for new work.
31
- DEFAULT_TIMER_OPTIONS = {
32
- execution_interval: Configuration::DEFAULT_POLL_INTERVAL,
33
- timeout_interval: 1,
34
- run_now: true,
35
- }.freeze
36
-
37
29
  # @!attribute [r] instances
38
30
  # @!scope class
39
31
  # List of all instantiated Schedulers in the current process.
@@ -41,7 +33,6 @@ module GoodJob # :nodoc:
41
33
  cattr_reader :instances, default: [], instance_reader: false
42
34
 
43
35
  # Creates GoodJob::Scheduler(s) and Performers from a GoodJob::Configuration instance.
44
- # TODO: move this to GoodJob::Configuration
45
36
  # @param configuration [GoodJob::Configuration]
46
37
  # @return [GoodJob::Scheduler, GoodJob::MultiScheduler]
47
38
  def self.from_configuration(configuration)
@@ -53,7 +44,7 @@ module GoodJob # :nodoc:
53
44
  parsed = GoodJob::Job.queue_parser(queue_string)
54
45
  job_filter = proc do |state|
55
46
  if parsed[:exclude]
56
- !parsed[:exclude].include? state[:queue_name]
47
+ parsed[:exclude].exclude?(state[:queue_name])
57
48
  elsif parsed[:include]
58
49
  parsed[:include].include? state[:queue_name]
59
50
  else
@@ -62,7 +53,7 @@ module GoodJob # :nodoc:
62
53
  end
63
54
  job_performer = GoodJob::Performer.new(job_query, :perform_with_advisory_lock, name: queue_string, filter: job_filter)
64
55
 
65
- GoodJob::Scheduler.new(job_performer, max_threads: max_threads, poll_interval: configuration.poll_interval)
56
+ GoodJob::Scheduler.new(job_performer, max_threads: max_threads)
66
57
  end
67
58
 
68
59
  if schedulers.size > 1
@@ -73,23 +64,19 @@ module GoodJob # :nodoc:
73
64
  end
74
65
 
75
66
  # @param performer [GoodJob::Performer]
76
- # @param max_threads [Numeric, nil] the number of execution threads to use
77
- # @param poll_interval [Numeric, nil] the number of seconds between polls for jobs
78
- def initialize(performer, max_threads: nil, poll_interval: nil)
67
+ # @param max_threads [Numeric, nil] number of seconds between polls for jobs
68
+ def initialize(performer, max_threads: nil)
79
69
  raise ArgumentError, "Performer argument must implement #next" unless performer.respond_to?(:next)
80
70
 
81
71
  self.class.instances << self
82
72
 
83
73
  @performer = performer
84
74
 
85
- @timer_options = DEFAULT_TIMER_OPTIONS.dup
86
- @timer_options[:execution_interval] = poll_interval if poll_interval.present?
87
-
88
75
  @pool_options = DEFAULT_POOL_OPTIONS.dup
89
76
  @pool_options[:max_threads] = max_threads if max_threads.present?
90
- @pool_options[:name] = "GoodJob::Scheduler(queues=#{@performer.name} max_threads=#{@pool_options[:max_threads]} poll_interval=#{@timer_options[:execution_interval]})"
77
+ @pool_options[:name] = "GoodJob::Scheduler(queues=#{@performer.name} max_threads=#{@pool_options[:max_threads]})"
91
78
 
92
- create_pools
79
+ create_pool
93
80
  end
94
81
 
95
82
  # Shut down the scheduler.
@@ -100,28 +87,20 @@ module GoodJob # :nodoc:
100
87
  # @param wait [Boolean] Wait for actively executing jobs to finish
101
88
  # @return [void]
102
89
  def shutdown(wait: true)
103
- @_shutdown = true
90
+ return unless @pool&.running?
104
91
 
105
92
  instrument("scheduler_shutdown_start", { wait: wait })
106
93
  instrument("scheduler_shutdown", { wait: wait }) do
107
- if @timer&.running?
108
- @timer.shutdown
109
- @timer.wait_for_termination if wait
110
- # TODO: Should be killed if wait is not true
111
- end
112
-
113
- if @pool&.running?
114
- @pool.shutdown
115
- @pool.wait_for_termination if wait
116
- # TODO: Should be killed if wait is not true
117
- end
94
+ @pool.shutdown
95
+ @pool.wait_for_termination if wait
96
+ # TODO: Should be killed if wait is not true
118
97
  end
119
98
  end
120
99
 
121
100
  # Tests whether the scheduler is shutdown.
122
101
  # @return [true, false, nil]
123
102
  def shutdown?
124
- @_shutdown
103
+ !@pool&.running?
125
104
  end
126
105
 
127
106
  # Restart the Scheduler.
@@ -131,8 +110,7 @@ module GoodJob # :nodoc:
131
110
  def restart(wait: true)
132
111
  instrument("scheduler_restart_pools") do
133
112
  shutdown(wait: wait) unless shutdown?
134
- create_pools
135
- @_shutdown = false
113
+ create_pool
136
114
  end
137
115
  end
138
116
 
@@ -157,14 +135,6 @@ module GoodJob # :nodoc:
157
135
  true
158
136
  end
159
137
 
160
- # Invoked on completion of TimerTask task.
161
- # @!visibility private
162
- # @return [void]
163
- def timer_observer(time, executed_task, thread_error)
164
- GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
165
- instrument("finished_timer_task", { result: executed_task, error: thread_error, time: time })
166
- end
167
-
168
138
  # Invoked on completion of ThreadPoolExecutor task
169
139
  # @!visibility private
170
140
  # @return [void]
@@ -176,14 +146,9 @@ module GoodJob # :nodoc:
176
146
 
177
147
  private
178
148
 
179
- def create_pools
180
- instrument("scheduler_create_pools", { performer_name: @performer.name, max_threads: @pool_options[:max_threads], poll_interval: @timer_options[:execution_interval] }) do
149
+ def create_pool
150
+ instrument("scheduler_create_pool", { performer_name: @performer.name, max_threads: @pool_options[:max_threads] }) do
181
151
  @pool = ThreadPoolExecutor.new(@pool_options)
182
- next unless @timer_options[:execution_interval].positive?
183
-
184
- @timer = Concurrent::TimerTask.new(@timer_options) { create_thread }
185
- @timer.add_observer(self, :timer_observer)
186
- @timer.execute
187
152
  end
188
153
  end
189
154
 
@@ -196,20 +161,20 @@ module GoodJob # :nodoc:
196
161
 
197
162
  ActiveSupport::Notifications.instrument("#{name}.good_job", payload, &block)
198
163
  end
199
- end
200
164
 
201
- # Custom sub-class of +Concurrent::ThreadPoolExecutor+ to add additional worker status.
202
- # @private
203
- class ThreadPoolExecutor < Concurrent::ThreadPoolExecutor
204
- # Number of inactive threads available to execute tasks.
205
- # https://github.com/ruby-concurrency/concurrent-ruby/issues/684#issuecomment-427594437
206
- # @return [Integer]
207
- def ready_worker_count
208
- synchronize do
209
- workers_still_to_be_created = @max_length - @pool.length
210
- workers_created_but_waiting = @ready.length
211
-
212
- workers_still_to_be_created + workers_created_but_waiting
165
+ # Custom sub-class of +Concurrent::ThreadPoolExecutor+ to add additional worker status.
166
+ # @private
167
+ class ThreadPoolExecutor < Concurrent::ThreadPoolExecutor
168
+ # Number of inactive threads available to execute tasks.
169
+ # https://github.com/ruby-concurrency/concurrent-ruby/issues/684#issuecomment-427594437
170
+ # @return [Integer]
171
+ def ready_worker_count
172
+ synchronize do
173
+ workers_still_to_be_created = @max_length - @pool.length
174
+ workers_created_but_waiting = @ready.length
175
+
176
+ workers_still_to_be_created + workers_created_but_waiting
177
+ end
213
178
  end
214
179
  end
215
180
  end
@@ -1,4 +1,4 @@
1
1
  module GoodJob
2
2
  # GoodJob gem version.
3
- VERSION = '1.3.0'.freeze
3
+ VERSION = '1.3.1'.freeze
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-03 00:00:00.000000000 Z
11
+ date: 2020-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -290,6 +290,20 @@ dependencies:
290
290
  - - ">="
291
291
  - !ruby/object:Gem::Version
292
292
  version: '0'
293
+ - !ruby/object:Gem::Dependency
294
+ name: rails
295
+ requirement: !ruby/object:Gem::Requirement
296
+ requirements:
297
+ - - ">="
298
+ - !ruby/object:Gem::Version
299
+ version: '0'
300
+ type: :development
301
+ prerelease: false
302
+ version_requirements: !ruby/object:Gem::Requirement
303
+ requirements:
304
+ - - ">="
305
+ - !ruby/object:Gem::Version
306
+ version: '0'
293
307
  - !ruby/object:Gem::Dependency
294
308
  name: rbtrace
295
309
  requirement: !ruby/object:Gem::Requirement
@@ -475,6 +489,7 @@ files:
475
489
  - lib/good_job/multi_scheduler.rb
476
490
  - lib/good_job/notifier.rb
477
491
  - lib/good_job/performer.rb
492
+ - lib/good_job/poller.rb
478
493
  - lib/good_job/railtie.rb
479
494
  - lib/good_job/scheduler.rb
480
495
  - lib/good_job/version.rb
@@ -510,7 +525,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
510
525
  - !ruby/object:Gem::Version
511
526
  version: '0'
512
527
  requirements: []
513
- rubygems_version: 3.0.3
528
+ rubygems_version: 3.1.4
514
529
  signing_key:
515
530
  specification_version: 4
516
531
  summary: A multithreaded, Postgres-based ActiveJob backend for Ruby on Rails