good_job 1.3.0 → 1.3.1

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: 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