sucker_punch 2.0.1 → 3.0.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
- SHA1:
3
- metadata.gz: bf92e4a48564bae41998ae57c236a47b89285dbc
4
- data.tar.gz: 52889bcf6c537626a756ed72b9aa384426c38e72
2
+ SHA256:
3
+ metadata.gz: e1edad787473a077f23f2fae95150cdb92e3834a12150fbd4d910fade5692516
4
+ data.tar.gz: 4ba7b7fa6cf3a1c99706a3bda43b0fd2fc291ae1825a23466b00a5b7a3354003
5
5
  SHA512:
6
- metadata.gz: ebf79f943dd84a524c613556efbe009d022c85aa111675170abbceb2d7ac5b45b09cedf273846fd963e0e4ae13eb0f82c427ca72d8407687a9fd0be85fe5f587
7
- data.tar.gz: 1e8c7a238309b242624cc3a594efa1efd371f9fccccdabb76ab8ddb884972ce0956adf99969a6c7b7a63955555c1595d55e0472dc1f17a0875c56ebe235b0bd5
6
+ metadata.gz: a8184cafe29937ad818920951c3c760e8435b4e35a348e27629053bae1b56e2f44ab412154fb3769e6878034a9351ad5e60fb44d9385bf5bb4f2bf58cc91c71c
7
+ data.tar.gz: fde16057612312085f59a955e783007b6a0cf0b4ff7d08312963bc0c76b3be2e5d254e5eb1df1625db3c554403485e5df8a1c995ab50b71dda4e1358b00e8d23
data/.travis.yml CHANGED
@@ -4,7 +4,8 @@ rvm:
4
4
  - 2.0.0
5
5
  - 2.1.8
6
6
  - 2.2.4
7
- - 2.3.0
7
+ - 2.3.4
8
+ - 2.4.1
8
9
  - ruby-head
9
10
 
10
11
  matrix:
data/CHANGES.md CHANGED
@@ -1,3 +1,49 @@
1
+ 3.0.0
2
+ -------
3
+ - Add support for keyword arguments in ruby `>= 3.0`. More details in [release notes](https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/).
4
+
5
+ 2.1.1
6
+ -------
7
+ - Relax versioning constraint of `concurrent-ruby` to make way for 1.1 release
8
+
9
+ 2.1.0
10
+ -------
11
+ - Add `max_jobs` configuration option to set the maximum number of tasks that
12
+ may be waiting in the work queue
13
+
14
+ ```ruby
15
+ class JobWithLimit
16
+ include SuckerPunch::Job
17
+ max_jobs 2
18
+
19
+ def perform(data)
20
+ # work...
21
+ end
22
+ end
23
+
24
+ 10.times do
25
+ begin
26
+ JobWithLimit.perform_async('work') }
27
+ rescue Concurrent::RejectedExecutionError => e
28
+ # Queue maxed out, this job didn't get queued
29
+ end
30
+ end
31
+
32
+ 2.0.4
33
+ -------
34
+ - Better initialization of variables and names to remove warnings
35
+
36
+ 2.0.3
37
+ -------
38
+ - Rewrite shutdown strategy to fix bug related to premature shutdown when only
39
+ 1 job is in enqueued when a job has more than 1 worker
40
+
41
+ 2.0.2
42
+ -------
43
+ - Don't consider global shutdown bool when exhausting the queue during
44
+ shutdown. This led to `shutdown_timeout` not being respected when
45
+ processing remaining jobs left in the queue with a high `shutdown_timeout`.
46
+
1
47
  2.0.1
2
48
  -------
3
49
  - Remove scripts from `bin/`
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Sucker Punch
2
2
 
3
- [![Build Status](https://travis-ci.org/brandonhilkert/sucker_punch.png?branch=master)](https://travis-ci.org/brandonhilkert/sucker_punch)
4
- [![Code Climate](https://codeclimate.com/github/brandonhilkert/sucker_punch.png)](https://codeclimate.com/github/brandonhilkert/sucker_punch)
3
+ [![Build Status](https://travis-ci.org/brandonhilkert/sucker_punch.svg?branch=master)](https://travis-ci.org/brandonhilkert/sucker_punch)
4
+ [![Code Climate](https://codeclimate.com/github/brandonhilkert/sucker_punch.svg)](https://codeclimate.com/github/brandonhilkert/sucker_punch)
5
5
 
6
6
  Sucker Punch is a single-process Ruby asynchronous processing library.
7
7
  This reduces costs
@@ -14,8 +14,7 @@ crunching, or social platform manipulation. No reason to hold up a
14
14
  user when you can do these things in the background within the same
15
15
  process as your web application...
16
16
 
17
- Sucker Punch is built on top of [concurrent-ruby]
18
- (https://github.com/ruby-concurrency/concurrent-ruby). Each job is setup as
17
+ Sucker Punch is built on top of [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby). Each job is setup as
19
18
  a pool, which equates to its own queue with individual workers working against
20
19
  the jobs. Unlike most other background processing libraries, Sucker
21
20
  Punch's jobs are stored in memory. The benefit to this is there is no
@@ -115,6 +114,22 @@ class LogJob
115
114
  end
116
115
  ```
117
116
 
117
+ #### Configure the Queue Size
118
+
119
+ The default number of jobs that can be queued is unlimited. If you wish to restrict this you can set
120
+ max\_jobs as follows:
121
+
122
+ ```Ruby
123
+ class LogJob
124
+ include SuckerPunch::Job
125
+ max_jobs 10
126
+
127
+ def perform(event)
128
+ Log.new(event).track
129
+ end
130
+ end
131
+ ```
132
+
118
133
  #### Executing Jobs in the Future
119
134
 
120
135
  Many background processing libraries have methods to perform operations after a
@@ -132,7 +147,7 @@ class DataJob
132
147
  end
133
148
 
134
149
  DataJob.perform_async("asdf") # immediately perform asynchronously
135
- DataJob.perform_in(60, "asdf") # `perform` will be excuted 60 sec. later
150
+ DataJob.perform_in(60, "asdf") # `perform` will be executed 60 sec. later
136
151
  ```
137
152
 
138
153
  #### `ActiveRecord` Connection Pool Connections
@@ -255,6 +270,19 @@ $ rails g sucker_punch:job logger
255
270
  would create the file `app/jobs/logger_job.rb` with a unimplemented `#perform`
256
271
  method.
257
272
 
273
+ ## Sinatra
274
+
275
+ If you're using Sucker Punch with Sinatra, you must require Sucker Punch before Sinatra:
276
+
277
+ ```ruby
278
+ # app.rb
279
+
280
+ require 'sucker_punch'
281
+ require 'sinatra'
282
+ ```
283
+
284
+ This will ensure Sucker Punch's `at_exit()` handler to clean up and shutdown queues does not happen **before** Sinatra *starts up* via its own `at_exit()` handler.
285
+
258
286
  ## Active Job
259
287
 
260
288
  Sucker Punch has been added as an Active Job adapter in Rails 4.2.
@@ -270,11 +298,11 @@ gem 'sucker_punch'
270
298
  And then configure the backend to use Sucker Punch:
271
299
 
272
300
  ```Ruby
273
- # config/initializers/sucker_punch.rb
274
- Rails.application.configure do
301
+ # config/application.rb
302
+ class Application < Rails::Application
303
+ # ...
275
304
  config.active_job.queue_adapter = :sucker_punch
276
305
  end
277
-
278
306
  ```
279
307
 
280
308
  If you want to use Sucker Punch version `2.0.0+` with Rails `< 5.0.0`, be sure
@@ -1,6 +1,6 @@
1
- class <%= class_name %>Job
1
+ class <%= class_name %>Job
2
2
  include SuckerPunch::Job
3
-
3
+
4
4
  def perform
5
5
  raise NotImplementedError
6
6
  end
data/lib/sucker_punch.rb CHANGED
@@ -10,12 +10,12 @@ module SuckerPunch
10
10
  RUNNING = Concurrent::AtomicBoolean.new(true)
11
11
 
12
12
  class << self
13
- def exception_handler=(handler)
14
- @exception_handler = handler
13
+ def exception_handler
14
+ @exception_handler ||= method(:default_exception_handler)
15
15
  end
16
16
 
17
- def exception_handler
18
- @exception_handler || method(:default_exception_handler)
17
+ def exception_handler=(handler)
18
+ @exception_handler = handler
19
19
  end
20
20
 
21
21
  def default_exception_handler(ex, klass, args)
@@ -26,11 +26,7 @@ module SuckerPunch
26
26
  end
27
27
 
28
28
  def logger
29
- @logger || default_logger
30
- end
31
-
32
- def logger=(log)
33
- @logger = (log ? log : Logger.new('/dev/null'))
29
+ @logger ||= default_logger
34
30
  end
35
31
 
36
32
  def default_logger
@@ -39,9 +35,13 @@ module SuckerPunch
39
35
  l
40
36
  end
41
37
 
38
+ def logger=(log)
39
+ @logger = (log ? log : Logger.new('/dev/null'))
40
+ end
41
+
42
42
  def shutdown_timeout
43
43
  # 10 seconds on heroku, minus a grace period
44
- @shutdown_timeout || 8
44
+ @shutdown_timeout ||= 8
45
45
  end
46
46
 
47
47
  def shutdown_timeout=(timeout)
@@ -10,9 +10,8 @@ module SuckerPunch
10
10
  @job = job
11
11
  end
12
12
 
13
- def perform(*args)
14
- @job.class.perform_async(*args)
13
+ def perform(*args, **kwargs)
14
+ @job.class.perform_async(*args, **kwargs)
15
15
  end
16
16
  end
17
17
  end
18
-
@@ -14,15 +14,17 @@ module SuckerPunch
14
14
  # To trigger asynchronous job:
15
15
  #
16
16
  # LogJob.perform_async(1, 2, 3)
17
- # LogJob.perform_in(60, 1, 2, 3) # `perform` will be excuted 60 sec. later
17
+ # LogJob.perform_in(60, 1, 2, 3) # `perform` will be executed 60 sec. later
18
18
  #
19
19
  # Note that perform_async is a class method, perform is an instance method.
20
20
  module Job
21
21
  def self.included(base)
22
22
  base.extend(ClassMethods)
23
23
  base.class_attribute :num_workers
24
+ base.class_attribute :num_jobs_max
24
25
 
25
26
  base.num_workers = 2
27
+ base.num_jobs_max = nil
26
28
  end
27
29
 
28
30
  def logger
@@ -30,17 +32,17 @@ module SuckerPunch
30
32
  end
31
33
 
32
34
  module ClassMethods
33
- def perform_async(*args)
35
+ def perform_async(*args, **kwargs)
34
36
  return unless SuckerPunch::RUNNING.true?
35
- queue = SuckerPunch::Queue.find_or_create(self.to_s, num_workers)
36
- queue.post(args) { |args| __run_perform(*args) }
37
+ queue = SuckerPunch::Queue.find_or_create(self.to_s, num_workers, num_jobs_max)
38
+ queue.post { __run_perform(*args, **kwargs) }
37
39
  end
38
40
 
39
- def perform_in(interval, *args)
41
+ def perform_in(interval, *args, **kwargs)
40
42
  return unless SuckerPunch::RUNNING.true?
41
- queue = SuckerPunch::Queue.find_or_create(self.to_s, num_workers)
43
+ queue = SuckerPunch::Queue.find_or_create(self.to_s, num_workers, num_jobs_max)
42
44
  job = Concurrent::ScheduledTask.execute(interval.to_f, args: args, executor: queue) do
43
- __run_perform(*args)
45
+ __run_perform(*args, **kwargs)
44
46
  end
45
47
  job.pending?
46
48
  end
@@ -49,17 +51,24 @@ module SuckerPunch
49
51
  self.num_workers = num
50
52
  end
51
53
 
52
- def __run_perform(*args)
53
- # break if shutdown began while I was waiting in the queue
54
- return unless SuckerPunch::RUNNING.true?
54
+ def max_jobs(num)
55
+ self.num_jobs_max = num
56
+ end
55
57
 
58
+ def __run_perform(*args, **kwargs)
56
59
  SuckerPunch::Counter::Busy.new(self.to_s).increment
57
- result = self.new.perform(*args)
60
+
61
+ result = if RUBY_VERSION >= '2.5'
62
+ self.new.perform(*args, **kwargs)
63
+ else
64
+ self.new.perform(*args, *(kwargs.any? ? [kwargs] : nil))
65
+ end
66
+
58
67
  SuckerPunch::Counter::Processed.new(self.to_s).increment
59
68
  result
60
69
  rescue => ex
61
70
  SuckerPunch::Counter::Failed.new(self.to_s).increment
62
- SuckerPunch.exception_handler.call(ex, self, args)
71
+ SuckerPunch.exception_handler.call(ex, self, [*args, **kwargs])
63
72
  ensure
64
73
  SuckerPunch::Counter::Busy.new(self.to_s).decrement
65
74
  end
@@ -5,23 +5,26 @@ module SuckerPunch
5
5
  extend Forwardable
6
6
  include Concurrent::ExecutorService
7
7
 
8
+ DEFAULT_MAX_QUEUE_SIZE = 0 # Unlimited
9
+
8
10
  DEFAULT_EXECUTOR_OPTIONS = {
9
11
  min_threads: 2,
10
12
  max_threads: 2,
11
13
  idletime: 60, # 1 minute
12
- max_queue: 0, # unlimited
13
14
  auto_terminate: false # Let shutdown modes handle thread termination
14
15
  }.freeze
15
16
 
16
17
  QUEUES = Concurrent::Map.new
17
18
 
18
- def self.find_or_create(name, num_workers = 2)
19
+ def self.find_or_create(name, num_workers = 2, num_jobs_max = nil)
19
20
  pool = QUEUES.fetch_or_store(name) do
20
- options = DEFAULT_EXECUTOR_OPTIONS.merge({
21
- min_threads: num_workers,
22
- max_threads: num_workers
23
- })
24
- Concurrent::ThreadPoolExecutor.new(options)
21
+ options = DEFAULT_EXECUTOR_OPTIONS
22
+ .merge(
23
+ min_threads: num_workers,
24
+ max_threads: num_workers,
25
+ max_queue: num_jobs_max || DEFAULT_MAX_QUEUE_SIZE
26
+ )
27
+ Concurrent::ThreadPoolExecutor.new(**options)
25
28
  end
26
29
 
27
30
  new(name, pool)
@@ -66,21 +69,43 @@ module SuckerPunch
66
69
  queues
67
70
  end
68
71
 
72
+ PAUSE_TIME = STDOUT.tty? ? 0.1 : 0.5
73
+
69
74
  def self.shutdown_all
75
+ deadline = Time.now + SuckerPunch.shutdown_timeout
76
+
70
77
  if SuckerPunch::RUNNING.make_false
78
+ # If a job is enqueued right before the script exits
79
+ # (command line, rake task, etc.), the system needs an
80
+ # interval to allow the enqueue jobs to make it in to the system
81
+ # otherwise the queue will look idle
82
+ sleep PAUSE_TIME
71
83
 
72
84
  queues = all
73
- latch = Concurrent::CountDownLatch.new(queues.length)
74
85
 
75
- queues.each do |queue|
76
- queue.post(latch) { |l| l.count_down }
77
- queue.shutdown
78
- end
86
+ # Issue shutdown to each queue and let them wrap up their work. This
87
+ # prevents new jobs from being enqueued and lets the pool clean up
88
+ # after itself
89
+ queues.each { |queue| queue.shutdown }
90
+
91
+ # return if every queue is empty and workers in every queue are idle
92
+ return if queues.all? { |queue| queue.idle? }
93
+
94
+ SuckerPunch.logger.info("Pausing to allow workers to finish...")
79
95
 
80
- unless latch.wait(SuckerPunch.shutdown_timeout)
81
- queues.each { |queue| queue.kill }
82
- SuckerPunch.logger.info("Queued jobs didn't finish before shutdown_timeout...killing remaining jobs")
96
+ remaining = deadline - Time.now
97
+
98
+ # Continue to loop through each queue and test if it's idle, while
99
+ # respecting the shutdown timeout
100
+ while remaining > PAUSE_TIME
101
+ return if queues.all? { |queue| queue.idle? }
102
+ sleep PAUSE_TIME
103
+ remaining = deadline - Time.now
83
104
  end
105
+
106
+ # Queues haven't finished work. Aggressively kill them.
107
+ SuckerPunch.logger.warn("Queued jobs didn't finish before shutdown_timeout...killing remaining jobs")
108
+ queues.each { |queue| queue.kill }
84
109
  end
85
110
  end
86
111
 
@@ -89,6 +114,7 @@ module SuckerPunch
89
114
  def_delegators :@pool,
90
115
  :max_length,
91
116
  :min_length,
117
+ :max_queue,
92
118
  :length,
93
119
  :queue_length,
94
120
  :wait_for_termination#,
@@ -115,6 +141,10 @@ module SuckerPunch
115
141
  synchronize { @running }
116
142
  end
117
143
 
144
+ def idle?
145
+ enqueued_jobs == 0 && busy_workers == 0
146
+ end
147
+
118
148
  def ==(other)
119
149
  pool == other.pool
120
150
  end
@@ -135,10 +165,10 @@ module SuckerPunch
135
165
  SuckerPunch::Counter::Failed.new(name).value
136
166
  end
137
167
 
138
- def post(*args, &block)
168
+ def post(*args, **kwargs, &block)
139
169
  synchronize do
140
170
  if @running
141
- @pool.post(*args, &block)
171
+ @pool.post(*args, **kwargs, &block)
142
172
  else
143
173
  false
144
174
  end
@@ -146,15 +176,12 @@ module SuckerPunch
146
176
  end
147
177
 
148
178
  def kill
149
- if can_initiate_shutdown?
150
- @pool.kill
151
- end
179
+ @pool.kill
152
180
  end
153
181
 
154
182
  def shutdown
155
- if can_initiate_shutdown?
156
- @pool.shutdown
157
- end
183
+ synchronize { @running = false }
184
+ @pool.shutdown
158
185
  end
159
186
 
160
187
  protected
@@ -162,19 +189,5 @@ module SuckerPunch
162
189
  def pool
163
190
  @pool
164
191
  end
165
-
166
- private
167
-
168
- def can_initiate_shutdown?
169
- synchronize do
170
- if @running
171
- @running = false
172
- true
173
- else
174
- false
175
- end
176
- end
177
- end
178
192
  end
179
193
  end
180
-
@@ -0,0 +1,44 @@
1
+ require 'sucker_punch'
2
+
3
+ # Include this in your tests to simulate
4
+ # a fake job queue. Jobs won't be executed
5
+ # as they normal would be the thread pool.
6
+ # They'll instead be pushed to a fake queue
7
+ # to be checked in a test environment.
8
+ #
9
+ # Include in your test_helper.rb:
10
+ #
11
+ # require 'sucker_punch/testing'
12
+ #
13
+ # In your application code:
14
+ #
15
+ # LogJob.perform_async(1, 2, 3)
16
+ #
17
+ # In your tests:
18
+ #
19
+ # LogJob.jobs => [{ "args" => [1, 2, 3]]
20
+
21
+ module SuckerPunch
22
+ module Job
23
+ def self.jobs
24
+ SuckerPunch::Queue.find_or_create(self.to_s)
25
+ end
26
+
27
+ def self.clear_all
28
+
29
+ end
30
+ end
31
+
32
+ class Queue
33
+ def self.find_or_create(name, _number_workers = 2, _num_jobs_max = nil)
34
+ QUEUES.fetch_or_store(name) do
35
+ []
36
+ end
37
+ end
38
+
39
+
40
+ def kill
41
+ true
42
+ end
43
+ end
44
+ end
@@ -17,7 +17,7 @@ require 'sucker_punch'
17
17
  #
18
18
  # Include inline testing lib:
19
19
  #
20
- # require 'sucker_punch/testing/inline"
20
+ # require 'sucker_punch/testing/inline'
21
21
  #
22
22
  # LogJob.perform_async(1, 2, 3) is now synchronous
23
23
  # LogJob.perform_in(1, 2, 3) is now synchronous
@@ -25,12 +25,12 @@ require 'sucker_punch'
25
25
  module SuckerPunch
26
26
  module Job
27
27
  module ClassMethods
28
- def perform_async(*args)
29
- self.new.perform(*args)
28
+ def perform_async(*args, **kwargs)
29
+ self.new.perform(*args, **kwargs)
30
30
  end
31
31
 
32
- def perform_in(_, *args)
33
- self.new.perform(*args)
32
+ def perform_in(_, *args, **kwargs)
33
+ self.new.perform(*args, **kwargs)
34
34
  end
35
35
  end
36
36
  end
@@ -1,3 +1,3 @@
1
1
  module SuckerPunch
2
- VERSION = "2.0.1"
2
+ VERSION = "3.0.0"
3
3
  end
data/sucker_punch.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
9
9
  gem.authors = ["Brandon Hilkert"]
10
10
  gem.email = ["brandonhilkert@gmail.com"]
11
11
  gem.description = %q{Asynchronous processing library for Ruby}
12
- gem.summary = %q{Sucker Punch is a Ruby asynchronous processing using Celluloid, heavily influenced by Sidekiq and girl_friday.}
12
+ gem.summary = %q{Sucker Punch is a Ruby asynchronous processing using concurrent-ruby, heavily influenced by Sidekiq and girl_friday.}
13
13
  gem.homepage = "https://github.com/brandonhilkert/sucker_punch"
14
14
  gem.license = "MIT"
15
15
 
@@ -18,11 +18,17 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.require_paths = ["lib"]
20
20
 
21
- gem.post_install_message = "Sucker Punch v2.0 introduces backwards-incompatible changes.\nPlease see https://github.com/brandonhilkert/sucker_punch/blob/master/CHANGES.md#20 for details."
21
+ gem.post_install_message = "Sucker Punch v2.0 introduces backwards-incompatible changes.\nPlease see https://github.com/brandonhilkert/sucker_punch/blob/master/CHANGES.md#200 for details."
22
22
 
23
23
  gem.add_development_dependency "rake", "~> 10.0"
24
24
  gem.add_development_dependency "minitest"
25
25
  gem.add_development_dependency "pry"
26
26
 
27
- gem.add_dependency "concurrent-ruby", "~> 1.0.0"
27
+ gem.add_dependency "concurrent-ruby", "~> 1.0"
28
+
29
+ if gem.respond_to?(:metadata)
30
+ gem.metadata['changelog_uri'] = 'https://github.com/brandonhilkert/sucker_punch/blob/master/CHANGES.md'
31
+ gem.metadata['source_code_uri'] = 'https://github.com/brandonhilkert/sucker_punch'
32
+ gem.metadata['bug_tracker_uri'] = 'https://github.com/brandonhilkert/sucker_punch/issues'
33
+ end
28
34
  end
@@ -55,6 +55,11 @@ module SuckerPunch
55
55
  FakeLogJob.workers(2)
56
56
  end
57
57
 
58
+ def test_can_set_max_jobs
59
+ FakeLogJob.max_jobs(10)
60
+ assert_equal 10, FakeLogJob.num_jobs_max
61
+ end
62
+
58
63
  def test_logger_is_accessible_from_instance
59
64
  SuckerPunch.logger = SuckerPunch.default_logger
60
65
  assert_equal SuckerPunch.logger, FakeLogJob.new.logger
@@ -177,4 +182,3 @@ module SuckerPunch
177
182
  end
178
183
  end
179
184
  end
180
-
@@ -29,6 +29,11 @@ module SuckerPunch
29
29
  assert_equal 4, queue.min_length
30
30
  end
31
31
 
32
+ def test_queue_max_queue_can_be_set
33
+ queue = SuckerPunch::Queue.find_or_create(@queue, 4, 10)
34
+ assert_equal(10, queue.max_queue)
35
+ end
36
+
32
37
  def test_same_queue_is_returned_on_subsequent_queries
33
38
  queue = SuckerPunch::Queue.find_or_create(@queue)
34
39
  assert_equal queue, SuckerPunch::Queue.find_or_create(@queue)
@@ -82,33 +87,29 @@ module SuckerPunch
82
87
  assert_equal true, queue.running?
83
88
  end
84
89
 
85
- def test_jobs_can_be_posted_to_pool
86
- arr = []
87
- fake_pool = FakePool.new
88
- queue = SuckerPunch::Queue.new "fake", fake_pool
89
- queue.post(1, 2) { |args| arr.push args }
90
- assert_equal [1, 2], arr.first
90
+ def test_idle_considers_queue_workers_and_length
91
+ queue = SuckerPunch::Queue.find_or_create(FakeNilJob.to_s)
92
+ assert_equal true, queue.idle?
91
93
  end
92
94
 
93
- def test_jobs_arent_posted_if_queue_isnt_running
95
+ def test_jobs_can_be_posted_to_pool
94
96
  arr = []
95
97
  fake_pool = FakePool.new
96
- queue = SuckerPunch::Queue.new "fake", fake_pool
97
- queue.kill
98
+ queue = SuckerPunch::Queue.new "fake", fake_pool
98
99
  queue.post(1, 2) { |args| arr.push args }
99
- assert arr.empty?
100
+ assert_equal [1, 2], arr.first
100
101
  end
101
102
 
102
103
  def test_kill_sends_kill_to_pool
103
104
  fake_pool = FakePool.new
104
- queue = SuckerPunch::Queue.new "fake", fake_pool
105
+ queue = SuckerPunch::Queue.new "fake", fake_pool
105
106
  queue.kill
106
107
  assert_equal :kill, fake_pool.signals.first
107
108
  end
108
109
 
109
110
  def test_shutdown_sends_shutdown_to_pool
110
111
  fake_pool = FakePool.new
111
- queue = SuckerPunch::Queue.new "fake", fake_pool
112
+ queue = SuckerPunch::Queue.new "fake", fake_pool
112
113
  queue.shutdown
113
114
  assert_equal :shutdown, fake_pool.signals.first
114
115
  end
@@ -135,9 +136,9 @@ module SuckerPunch
135
136
  @signals = []
136
137
  end
137
138
 
138
- def post(*args, &block)
139
+ def post(*args, **kwargs, &block)
139
140
  if block_given?
140
- block.call(args)
141
+ block.call(args, **kwargs)
141
142
  end
142
143
  end
143
144
 
@@ -41,7 +41,7 @@ class SuckerPunchTest < Minitest::Test
41
41
  end
42
42
 
43
43
  def test_exception_handler_can_be_set
44
- SuckerPunch.exception_handler = -> (ex, _, _) { raise "bad stuff" }
44
+ SuckerPunch.exception_handler = -> (_ex, _, _) { raise "bad stuff" }
45
45
  assert_raises(::RuntimeError) { SuckerPunch.exception_handler.call(StandardError.new("bad"), nil, nil) }
46
46
  end
47
47
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sucker_punch
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Hilkert
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-14 00:00:00.000000000 Z
11
+ date: 2021-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.0.0
61
+ version: '1.0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.0.0
68
+ version: '1.0'
69
69
  description: Asynchronous processing library for Ruby
70
70
  email:
71
71
  - brandonhilkert@gmail.com
@@ -89,6 +89,7 @@ files:
89
89
  - lib/sucker_punch/job.rb
90
90
  - lib/sucker_punch/queue.rb
91
91
  - lib/sucker_punch/railtie.rb
92
+ - lib/sucker_punch/testing.rb
92
93
  - lib/sucker_punch/testing/inline.rb
93
94
  - lib/sucker_punch/version.rb
94
95
  - sucker_punch.gemspec
@@ -101,10 +102,13 @@ files:
101
102
  homepage: https://github.com/brandonhilkert/sucker_punch
102
103
  licenses:
103
104
  - MIT
104
- metadata: {}
105
+ metadata:
106
+ changelog_uri: https://github.com/brandonhilkert/sucker_punch/blob/master/CHANGES.md
107
+ source_code_uri: https://github.com/brandonhilkert/sucker_punch
108
+ bug_tracker_uri: https://github.com/brandonhilkert/sucker_punch/issues
105
109
  post_install_message: |-
106
110
  Sucker Punch v2.0 introduces backwards-incompatible changes.
107
- Please see https://github.com/brandonhilkert/sucker_punch/blob/master/CHANGES.md#20 for details.
111
+ Please see https://github.com/brandonhilkert/sucker_punch/blob/master/CHANGES.md#200 for details.
108
112
  rdoc_options: []
109
113
  require_paths:
110
114
  - lib
@@ -119,12 +123,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
123
  - !ruby/object:Gem::Version
120
124
  version: '0'
121
125
  requirements: []
122
- rubyforge_project:
123
- rubygems_version: 2.5.1
124
- signing_key:
126
+ rubygems_version: 3.1.2
127
+ signing_key:
125
128
  specification_version: 4
126
- summary: Sucker Punch is a Ruby asynchronous processing using Celluloid, heavily influenced
127
- by Sidekiq and girl_friday.
129
+ summary: Sucker Punch is a Ruby asynchronous processing using concurrent-ruby, heavily
130
+ influenced by Sidekiq and girl_friday.
128
131
  test_files:
129
132
  - test/sucker_punch/async_syntax_test.rb
130
133
  - test/sucker_punch/counter_test.rb