shoryuken 0.0.3 → 0.0.4

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
  SHA1:
3
- metadata.gz: 3afa1e42164a3fc885caf45222d317ac77692c3b
4
- data.tar.gz: 9abfa8e2c9ed9b4540bbb422fba35a3f00591364
3
+ metadata.gz: 70a39ae890a6fe9dcff44b0c6ceeab9c77931ab2
4
+ data.tar.gz: ff223f629ed2f60cc0abb32fa17f28e15d680d2f
5
5
  SHA512:
6
- metadata.gz: 35934726404b3d5454b1bc97875d3ba8934d2ef4efa4a354dbff97af95959c647757259ffc6fefc53a8ffaab5c1cfeffad73d79aff50a3575f5e65d39cbbb553
7
- data.tar.gz: 6cafc6fbfd06fff62541acc41169877440454eba4afb1688728bbd69330ed53fa9a62d1c28b2b9a057de853952cff26d537d013747a8cc5b6c47a8b637f3c1f2
6
+ metadata.gz: f0afdb29904c40200d1976f2b26973ae6694e7018b07bf133153c355e250a1d613cf1fd9c0500c2aaa612d77f4c5d631823ab186642b4a2051a76ea78feea4e6
7
+ data.tar.gz: 8b3d0dc3f255b3d921386a322e645e7875f2962c902094a48671d24a95211b02e5f0558be53e30619baf92551e9f3d7e23b60def11a2c11b84107525e339f141
data/README.md CHANGED
@@ -30,13 +30,12 @@ If `high_priority` gets empty, Shoryuken will keep using the 25 processors, but
30
30
 
31
31
  If `high_priority` receives a new message, Shoryuken will smoothly increase back the `high_priority` weight one by one until it reaches the weight of 6 again, which is the maximum configured for `high_priority`.
32
32
 
33
- If all queues get empty, all processors will be changed to the waiting state and the queues will be checked every `delay: 25`. If any queue receives a new message, Shoryuken will start processing again.
33
+ If all queues get empty, all processors will be changed to the waiting state and the queues will be checked every `delay: 25`. If any queue receives a new message, Shoryuken will start processing again. [Check the delay option documentation for more information](https://github.com/phstc/shoryuken/wiki/Shoryuken-options#delay).
34
34
 
35
- *You can set `delay: 0` to continuously check the queues without pausing even if they are empty.*
36
35
 
37
36
  ### Fetch in batches
38
37
 
39
- To be even more performance and cost efficient, Shoryuken fetches SQS messages in batches.
38
+ To be even more performance and cost efficient, Shoryuken fetches SQS messages in batches, so a single SQS request can fetch up to 10 messages.
40
39
 
41
40
  ## Installation
42
41
 
@@ -44,7 +43,7 @@ Add this line to your application's Gemfile:
44
43
 
45
44
  gem 'shoryuken'
46
45
 
47
- **Require Shoryuken from GitHub to get the latest updates:**
46
+ Or to get the latest updates:
48
47
 
49
48
  gem 'shoryuken', github: 'phstc/shoryuken', branch: 'master'
50
49
 
@@ -64,7 +63,7 @@ Or install it yourself as:
64
63
  class MyWorker
65
64
  include Shoryuken::Worker
66
65
 
67
- shoryuken_options queue: 'default', delete: true
66
+ shoryuken_options queue: 'default', auto_delete: true
68
67
  # shoryuken_options queue: ->{ "#{ENV['environment']_default" }
69
68
 
70
69
  # shoryuken_options body_parser: :json
@@ -81,16 +80,7 @@ end
81
80
 
82
81
  ### Sending a message
83
82
 
84
- ```ruby
85
- MyWorker.perform_async('Pablo')
86
- # or
87
- Shoryuken::Client.queues('default').send_message('Pablo')
88
-
89
- # delaying a message
90
- MyWorker.perform_async('Pablo', delay_seconds: 60)
91
- # or
92
- Shoryuken::Client.queues('default').send_message('Pablo', delay_seconds: 60)
93
- ```
83
+ [Check the Sending a message documentation](https://github.com/phstc/shoryuken/wiki/Sending-a-message)
94
84
 
95
85
  ### Midleware
96
86
 
@@ -128,6 +118,14 @@ queues:
128
118
  - [low_priority, 1]
129
119
  ```
130
120
 
121
+ ### Rails Integration
122
+
123
+ You can tell Shoryuken to load your Rails application by passing the `-R` or `--rails` flag to the "shoryuken" command.
124
+
125
+ If you load Rails, and assuming your workers are located in the `app/workers` directory, they will be auto-loaded. This means you don't need to require them explicitly with `-r`.
126
+
127
+ This feature works for Rails 4+, but needs to be confirmed for older versions.
128
+
131
129
  ### Start Shoryuken
132
130
 
133
131
  ```shell
@@ -145,6 +143,7 @@ shoryuken [options]
145
143
  -q, --queue QUEUE[,WEIGHT]... Queues to process with optional weights
146
144
  -r, --require [PATH|DIR] Location of the worker
147
145
  -C, --config PATH Path to YAML config file
146
+ -R, --rails Attempts to load the containing Rails project
148
147
  -L, --logfile PATH Path to writable logfile
149
148
  -P, --pidfile PATH Path to pidfile
150
149
  -v, --verbose Print more verbose output
data/Rakefile CHANGED
@@ -21,27 +21,3 @@ task :console do
21
21
  ARGV.clear
22
22
  Pry.start
23
23
  end
24
-
25
- desc 'Push test messages to high_priority, default and low_priority'
26
- task :push_test, :size do |t, args|
27
- require 'yaml'
28
- require 'shoryuken'
29
-
30
- config = YAML.load File.read(File.join(File.expand_path('..', __FILE__), 'shoryuken.yml'))
31
-
32
- AWS.config(config['aws'])
33
-
34
- Shoryuken::Client.sqs.queues.create('default')
35
- Shoryuken::Client.sqs.queues.create('high_priority')
36
- Shoryuken::Client.sqs.queues.create('low_priority')
37
-
38
- (args[:size] || 1).to_i.times.map do |i|
39
- Thread.new do
40
- puts "Pushing test ##{i}"
41
-
42
- Shoryuken::Client.queues('high_priority').send_message("test #{i}")
43
- Shoryuken::Client.queues('default').send_message("test #{i}")
44
- Shoryuken::Client.queues('low_priority').send_message("test #{i}")
45
- end
46
- end.each &:join
47
- end
@@ -0,0 +1,20 @@
1
+ require 'yaml'
2
+ require 'shoryuken'
3
+
4
+ # load SQS credentials
5
+ config = YAML.load File.read(File.join(File.expand_path('..', __FILE__), 'shoryuken.yml'))
6
+
7
+ AWS.config(config['aws'])
8
+
9
+ sqs = AWS::SQS.new
10
+
11
+ # create a queue and a respective dead letter queue
12
+ # after 7 attempts SQS will move the message to the dead letter queue
13
+
14
+ dl_name = 'default_failures'
15
+ dl = sqs.queues.create(dl_name)
16
+
17
+ options = {}
18
+ options[:redrive_policy] = %Q{{"maxReceiveCount":"7", "deadLetterTargetArn":"#{dl.arn}"}"}
19
+
20
+ sqs.queues.create('default', options)
@@ -1,9 +1,20 @@
1
1
  class DefaultWorker
2
2
  include Shoryuken::Worker
3
3
 
4
- shoryuken_options queue: 'default', delete: true, body_parser: ->(sqs_msg){ "new body: #{sqs_msg.body}" }
4
+ shoryuken_options queue: 'default', auto_delete: true
5
5
 
6
6
  def perform(sqs_msg, body)
7
7
  puts "DefaultWorker: '#{body}'"
8
8
  end
9
9
  end
10
+
11
+ # multiple workers for the same queue
12
+ class DefaultWorker2
13
+ include Shoryuken::Worker
14
+
15
+ shoryuken_options queue: 'default', auto_delete: true
16
+
17
+ def perform(sqs_msg, body)
18
+ puts "DefaultWorker2: '#{body}'"
19
+ end
20
+ end
data/lib/shoryuken.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'yaml'
2
- require 'aws-sdk'
2
+ require 'aws-sdk-v1'
3
3
  require 'time'
4
4
 
5
5
  require 'shoryuken/version'
@@ -7,6 +7,7 @@ require 'shoryuken/core_ext'
7
7
  require 'shoryuken/util'
8
8
  require 'shoryuken/client'
9
9
  require 'shoryuken/worker'
10
+ require 'shoryuken/worker_loader'
10
11
  require 'shoryuken/logging'
11
12
  require 'shoryuken/middleware/chain'
12
13
  require 'shoryuken/middleware/server/auto_delete'
@@ -21,52 +22,75 @@ module Shoryuken
21
22
  timeout: 8
22
23
  }
23
24
 
24
- @@workers = {}
25
- @@queues = []
25
+ @@workers = {}
26
+ @@queues = []
27
+ @@worker_loader = WorkerLoader
26
28
 
27
- def self.options
28
- @options ||= DEFAULTS.dup
29
- end
29
+ class << self
30
+ def options
31
+ @options ||= DEFAULTS.dup
32
+ end
30
33
 
31
- def self.register_worker(queue, clazz)
32
- @@workers[queue] = clazz
33
- end
34
+ def register_worker(queue, clazz)
35
+ if worker_class = @@workers[queue]
36
+ if worker_class.get_shoryuken_options['batch'] == true || clazz.get_shoryuken_options['batch'] == true
37
+ raise ArgumentError, "Could not register #{clazz} for '#{queue}', "\
38
+ "because #{worker_class} is already registered for this queue, "\
39
+ "and Shoryuken doesn't support a batchable worker for a queue with multiple workers"
40
+ end
41
+ end
34
42
 
35
- def self.workers
36
- @@workers
37
- end
43
+ @@workers[queue] = clazz
44
+ end
38
45
 
39
- def self.queues
40
- @@queues
41
- end
46
+ def workers
47
+ @@workers
48
+ end
42
49
 
43
- def self.logger
44
- Shoryuken::Logging.logger
45
- end
50
+ def queues
51
+ @@queues
52
+ end
46
53
 
47
- # Shoryuken.configure_server do |config|
48
- # config.server_middleware do |chain|
49
- # chain.add MyServerHook
50
- # end
51
- # end
52
- def self.configure_server
53
- yield self
54
- end
54
+ def logger
55
+ Shoryuken::Logging.logger
56
+ end
55
57
 
56
- def self.server_middleware
57
- @server_chain ||= default_server_middleware
58
- yield @server_chain if block_given?
59
- @server_chain
60
- end
58
+ def worker_loader=(worker_loader)
59
+ @@worker_loader = worker_loader
60
+ end
61
+
62
+ def worker_loader
63
+ @@worker_loader
64
+ end
65
+
66
+ # Shoryuken.configure_server do |config|
67
+ # config.server_middleware do |chain|
68
+ # chain.add MyServerHook
69
+ # end
70
+ # end
71
+ def configure_server
72
+ yield self
73
+ end
74
+
75
+ def server_middleware
76
+ @server_chain ||= default_server_middleware
77
+ yield @server_chain if block_given?
78
+ @server_chain
79
+ end
61
80
 
62
81
 
63
- private
82
+ private
64
83
 
65
- def self.default_server_middleware
66
- Middleware::Chain.new do |m|
67
- m.add Middleware::Server::Timing
68
- m.add Middleware::Server::AutoDelete
69
- # TODO m.add Middleware::Server::RetryJobs
84
+ def default_server_middleware
85
+ Middleware::Chain.new do |m|
86
+ m.add Middleware::Server::Timing
87
+ m.add Middleware::Server::AutoDelete
88
+ if defined?(::ActiveRecord::Base)
89
+ require 'shoryuken/middleware/server/active_record'
90
+ m.add Middleware::Server::ActiveRecord
91
+ end
92
+ # TODO m.add Middleware::Server::RetryJobs
93
+ end
70
94
  end
71
95
  end
72
96
  end
data/lib/shoryuken/cli.rb CHANGED
@@ -22,7 +22,10 @@ module Shoryuken
22
22
  end
23
23
  end
24
24
 
25
- setup_options(args)
25
+ setup_options(args) do |cli_options|
26
+ # this needs to happen before configuration is parsed, since it may depend on Rails env
27
+ load_rails if cli_options[:rails]
28
+ end
26
29
  initialize_logger
27
30
  require_workers
28
31
  validate!
@@ -61,6 +64,25 @@ module Shoryuken
61
64
  require 'shoryuken/manager'
62
65
  end
63
66
 
67
+ def load_rails
68
+ # Adapted from: https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/cli.rb
69
+
70
+ require 'rails'
71
+ if ::Rails::VERSION::MAJOR < 4
72
+ require File.expand_path("config/environment.rb")
73
+ ::Rails.application.eager_load!
74
+ else
75
+ # Painful contortions, see 1791 for discussion
76
+ require File.expand_path("config/application.rb")
77
+ ::Rails::Application.initializer "shoryuken.eager_load" do
78
+ ::Rails.application.config.eager_load = true
79
+ end
80
+ require File.expand_path("config/environment.rb")
81
+ end
82
+
83
+ logger.info "Rails environment loaded"
84
+ end
85
+
64
86
  def daemonize
65
87
  return unless Shoryuken.options[:daemon]
66
88
 
@@ -125,6 +147,10 @@ module Shoryuken
125
147
  opts[:config_file] = arg
126
148
  end
127
149
 
150
+ o.on '-R', '--rails', 'Load Rails' do |arg|
151
+ opts[:rails] = arg
152
+ end
153
+
128
154
  o.on '-L', '--logfile PATH', 'Path to writable logfile' do |arg|
129
155
  opts[:logfile] = arg
130
156
  end
@@ -187,6 +213,9 @@ module Shoryuken
187
213
  def setup_options(args)
188
214
  options = parse_options(args)
189
215
 
216
+ # yield parsed options in case we need to do more setup before configuration is parsed
217
+ yield(options) if block_given?
218
+
190
219
  config = options[:config_file] ? parse_config(options[:config_file]).deep_symbolize_keys : {}
191
220
 
192
221
  Shoryuken.options.merge!(config)
@@ -213,8 +242,8 @@ module Shoryuken
213
242
  def validate!
214
243
  raise ArgumentError, 'No queues supplied' if Shoryuken.queues.empty?
215
244
 
216
- if queue_without_worker = Shoryuken.queues.find { |queue| Shoryuken.workers[queue].nil? }
217
- raise ArgumentError, "No worker supplied for #{queue_without_worker}"
245
+ Shoryuken.queues.each do |queue|
246
+ logger.warn "No worker supplied for '#{queue}'" unless Shoryuken.workers.include? queue
218
247
  end
219
248
 
220
249
  if Shoryuken.options[:aws][:access_key_id].nil? && Shoryuken.options[:aws][:secret_access_key].nil?
@@ -17,6 +17,8 @@ module Shoryuken
17
17
  end
18
18
 
19
19
  def send_message(queue, body, options = {})
20
+ body = JSON.dump(body) if body.is_a?(Hash)
21
+
20
22
  queues(queue).send_message(body, options)
21
23
  end
22
24
 
@@ -13,17 +13,22 @@ module Shoryuken
13
13
  # AWS limits the batch size by 10
14
14
  limit = limit > FETCH_LIMIT ? FETCH_LIMIT : limit
15
15
 
16
- Shoryuken::Client.receive_message queue, Shoryuken.options[:aws][:receive_message].to_h.merge(limit: limit)
16
+ options = Shoryuken.options[:aws][:receive_message].to_h
17
+ options[:limit] = limit
18
+ options[:message_attribute_names] ||= []
19
+ options[:message_attribute_names] << 'shoryuken_class'
20
+
21
+ Shoryuken::Client.receive_message queue, options
17
22
  end
18
23
 
19
24
  def fetch(queue, available_processors)
20
25
  watchdog('Fetcher#fetch died') do
21
26
  started_at = Time.now
22
27
 
23
- logger.info "Looking for new messages '#{queue}'"
28
+ logger.debug "Looking for new messages in '#{queue}'"
24
29
 
25
30
  begin
26
- batch = !!Shoryuken.workers[queue].get_shoryuken_options['batch']
31
+ batch = !!(Shoryuken.workers[queue] && Shoryuken.workers[queue].get_shoryuken_options['batch'])
27
32
 
28
33
  limit = batch ? FETCH_LIMIT : available_processors
29
34
 
@@ -38,7 +43,7 @@ module Shoryuken
38
43
 
39
44
  @manager.async.rebalance_queue_weight!(queue)
40
45
  else
41
- logger.info "No message found for '#{queue}'"
46
+ logger.debug "No message found for '#{queue}'"
42
47
 
43
48
  @manager.async.pause_queue!(queue)
44
49
  end
@@ -103,7 +103,7 @@ module Shoryuken
103
103
  def pause_queue!(queue)
104
104
  return if !@queues.include?(queue) || Shoryuken.options[:delay].to_f <= 0
105
105
 
106
- logger.info "Pausing '#{queue}' for #{Shoryuken.options[:delay].to_f} seconds, because it's empty"
106
+ logger.debug "Pausing '#{queue}' for #{Shoryuken.options[:delay].to_f} seconds, because it's empty"
107
107
 
108
108
  @queues.delete(queue)
109
109
 
@@ -139,7 +139,7 @@ module Shoryuken
139
139
  return if stopped?
140
140
 
141
141
  unless @queues.include? queue
142
- logger.info "Restarting '#{queue}'"
142
+ logger.debug "Restarting '#{queue}'"
143
143
 
144
144
  @queues << queue
145
145
 
@@ -169,7 +169,21 @@ module Shoryuken
169
169
  def next_queue
170
170
  return nil if @queues.empty?
171
171
 
172
+ # get/remove the first queue in the list
172
173
  queue = @queues.shift
174
+
175
+
176
+ unless Shoryuken.workers.include? queue
177
+ # when no worker registered pause the queue to avoid endless recursion
178
+
179
+ logger.debug "Pausing '#{queue}' for #{Shoryuken.options[:delay].to_f} seconds, because of no workers registered"
180
+
181
+ after(Shoryuken.options[:delay].to_f) { async.restart_queue!(queue) }
182
+
183
+ return next_queue
184
+ end
185
+
186
+ # add queue back to the end of the list
173
187
  @queues << queue
174
188
 
175
189
  queue
@@ -0,0 +1,13 @@
1
+ module Shoryuken
2
+ module Middleware
3
+ module Server
4
+ class ActiveRecord
5
+ def call(*args)
6
+ yield
7
+ ensure
8
+ ::ActiveRecord::Base.clear_active_connections!
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,14 +2,12 @@ module Shoryuken
2
2
  module Middleware
3
3
  module Server
4
4
  class AutoDelete
5
-
6
5
  def call(worker, queue, sqs_msg, body)
7
6
  yield
8
7
 
9
- # I'm still deciding, but `auto_delete` will be probably deprecated soon
10
- delete = worker.class.get_shoryuken_options['delete'] || worker.class.get_shoryuken_options['auto_delete']
8
+ auto_delete = worker.class.get_shoryuken_options['delete'] || worker.class.get_shoryuken_options['auto_delete']
11
9
 
12
- Shoryuken::Client.queues(queue).batch_delete(*Array(sqs_msg)) if delete
10
+ Shoryuken::Client.queues(queue).batch_delete(*Array(sqs_msg)) if auto_delete
13
11
  end
14
12
  end
15
13
  end
@@ -10,11 +10,10 @@ module Shoryuken
10
10
  end
11
11
 
12
12
  def process(queue, sqs_msg)
13
- worker_class = Shoryuken.workers[queue]
14
- defer do
15
- body = get_body(worker_class, sqs_msg)
13
+ worker = Shoryuken.worker_loader.call(queue, sqs_msg)
16
14
 
17
- worker = worker_class.new
15
+ defer do
16
+ body = get_body(worker.class, sqs_msg)
18
17
 
19
18
  Shoryuken.server_middleware.invoke(worker, queue, sqs_msg, body) do
20
19
  worker.perform(sqs_msg, body)
@@ -1,3 +1,3 @@
1
1
  module Shoryuken
2
- VERSION = '0.0.3'
2
+ VERSION = '0.0.4'
3
3
  end
@@ -6,19 +6,43 @@ module Shoryuken
6
6
 
7
7
  module ClassMethods
8
8
  def perform_async(body, options = {})
9
+ options ||= {}
10
+ options[:message_attributes] ||= {}
11
+ options[:message_attributes]['shoryuken_class'] = {
12
+ string_value: self.to_s,
13
+ data_type: 'String'
14
+ }
15
+
9
16
  Shoryuken::Client.send_message(get_shoryuken_options['queue'], body, options)
10
17
  end
11
18
 
19
+ def perform_in(interval, body, options = {})
20
+ interval = interval.to_f
21
+ now = Time.now.to_f
22
+ ts = (interval < 1_000_000_000 ? (now + interval).to_f : interval)
23
+
24
+ delay = (ts - now).ceil
25
+
26
+ raise 'The maximum allowed delay is 15 minutes' if delay > 15 * 60
27
+
28
+ perform_async(body, options.merge(delay_seconds: delay))
29
+ end
30
+
31
+ alias_method :perform_at, :perform_in
32
+
12
33
  def shoryuken_options(opts = {})
13
34
  @shoryuken_options = get_shoryuken_options.merge(stringify_keys(Hash(opts)))
14
35
  queue = @shoryuken_options['queue']
15
- queue = queue.call if queue.respond_to? :call
36
+ if queue.respond_to? :call
37
+ queue = queue.call
38
+ @shoryuken_options['queue'] = queue
39
+ end
16
40
 
17
41
  Shoryuken.register_worker(queue, self)
18
42
  end
19
43
 
20
44
  def get_shoryuken_options # :nodoc:
21
- @shoryuken_options || { 'queue' => 'default', 'delete' => false, 'batch' => false }
45
+ @shoryuken_options || { 'queue' => 'default', 'delete' => false, 'auto_delete' => false, 'batch' => false }
22
46
  end
23
47
 
24
48
  def stringify_keys(hash) # :nodoc:
@@ -0,0 +1,17 @@
1
+ module Shoryuken
2
+ class WorkerLoader
3
+ class << self
4
+ def call(queue, sqs_msg)
5
+ # missing `try?` - yes, I'm
6
+ worker_class = !sqs_msg.is_a?(Array) &&
7
+ sqs_msg.message_attributes &&
8
+ sqs_msg.message_attributes['shoryuken_class'] &&
9
+ sqs_msg.message_attributes['shoryuken_class'][:string_value]
10
+
11
+ worker_class = (worker_class.constantize rescue nil) || Shoryuken.workers[queue]
12
+
13
+ worker_class.new
14
+ end
15
+ end
16
+ end
17
+ end
data/shoryuken.gemspec CHANGED
@@ -22,6 +22,6 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rspec"
23
23
  spec.add_development_dependency "pry-byebug"
24
24
 
25
- spec.add_dependency "aws-sdk"
26
- spec.add_dependency "celluloid"
25
+ spec.add_dependency "aws-sdk-v1"
26
+ spec.add_dependency "celluloid", "~> 0.15.2"
27
27
  end
@@ -9,19 +9,45 @@ describe Shoryuken::Launcher do
9
9
  Shoryuken.options[:aws][:receive_message] ||= {}
10
10
  Shoryuken.options[:aws][:receive_message][:wait_time_seconds] = 5
11
11
 
12
+ Shoryuken.queues << 'shoryuken'
13
+ Shoryuken.queues << 'shoryuken_command'
14
+
15
+ Shoryuken.register_worker 'shoryuken', StandardWorker
16
+ Shoryuken.register_worker 'shoryuken_command', CommandWorker
17
+
12
18
  subject.run
13
19
 
14
- ShoryukenWorker.received_messages = 0
20
+ StandardWorker.received_messages = 0
15
21
  end
16
22
 
17
23
  after { subject.stop }
18
24
 
19
- class ShoryukenWorker
25
+ class CommandWorker
26
+ include Shoryuken::Worker
27
+
28
+ @@received_messages = 0
29
+
30
+ shoryuken_options queue: 'shoryuken_command', auto_delete: true
31
+
32
+ def perform(sqs_msg, body)
33
+ @@received_messages = Array(sqs_msg).size
34
+ end
35
+
36
+ def self.received_messages
37
+ @@received_messages
38
+ end
39
+
40
+ def self.received_messages=(received_messages)
41
+ @@received_messages = received_messages
42
+ end
43
+ end
44
+
45
+ class StandardWorker
20
46
  include Shoryuken::Worker
21
47
 
22
48
  @@received_messages = 0
23
49
 
24
- shoryuken_options queue: 'shoryuken', delete: true
50
+ shoryuken_options queue: 'shoryuken', auto_delete: true
25
51
 
26
52
  def perform(sqs_msg, body)
27
53
  @@received_messages = Array(sqs_msg).size
@@ -36,31 +62,42 @@ describe Shoryuken::Launcher do
36
62
  end
37
63
  end
38
64
 
65
+ it 'consumes as a command worker' do
66
+ CommandWorker.perform_async('Yo')
67
+
68
+ 10.times do
69
+ break if CommandWorker.received_messages > 0
70
+ sleep 1
71
+ end
72
+
73
+ expect(CommandWorker.received_messages).to eq 1
74
+ end
75
+
39
76
  it 'consumes a message' do
40
- ShoryukenWorker.get_shoryuken_options['batch'] = false
77
+ StandardWorker.get_shoryuken_options['batch'] = false
41
78
 
42
79
  Shoryuken::Client.queues('shoryuken').send_message('Yo')
43
80
 
44
81
  10.times do
45
- break if ShoryukenWorker.received_messages > 0
46
- sleep 0.2
82
+ break if StandardWorker.received_messages > 0
83
+ sleep 1
47
84
  end
48
85
 
49
- expect(ShoryukenWorker.received_messages).to eq 1
86
+ expect(StandardWorker.received_messages).to eq 1
50
87
  end
51
88
 
52
89
  it 'consumes a batch' do
53
- ShoryukenWorker.get_shoryuken_options['batch'] = true
90
+ StandardWorker.get_shoryuken_options['batch'] = true
54
91
 
55
92
  Shoryuken::Client.queues('shoryuken').batch_send *(['Yo'] * 10)
56
93
 
57
94
  10.times do
58
- break if ShoryukenWorker.received_messages > 0
59
- sleep 0.2
95
+ break if StandardWorker.received_messages > 0
96
+ sleep 1
60
97
  end
61
98
 
62
99
  # the fetch result is uncertain, should be greater than 1, but hard to tell the exact size
63
- expect(ShoryukenWorker.received_messages).to be > 1
100
+ expect(StandardWorker.received_messages).to be > 1
64
101
  end
65
102
  end
66
103
  end
@@ -33,6 +33,22 @@ describe Shoryuken::Client do
33
33
 
34
34
  described_class.send_message(queue, 'test2', delay_seconds: 60)
35
35
  end
36
+
37
+ it 'parsers as JSON by default' do
38
+ msg = { field: 'test', other_field: 'other' }
39
+
40
+ expect(sqs_queue).to receive(:send_message).with(JSON.dump(msg), {})
41
+
42
+ described_class.send_message(queue, msg)
43
+ end
44
+
45
+ it 'parsers as JSON by default and keep the options' do
46
+ msg = { field: 'test', other_field: 'other' }
47
+
48
+ expect(sqs_queue).to receive(:send_message).with(JSON.dump(msg), { delay_seconds: 60 })
49
+
50
+ described_class.send_message(queue, msg, delay_seconds: 60)
51
+ end
36
52
  end
37
53
 
38
54
  describe '.visibility_timeout' do
@@ -18,7 +18,7 @@ describe Shoryuken::Fetcher do
18
18
 
19
19
  describe '#fetch' do
20
20
  it 'calls pause when no message' do
21
- allow(sqs_queue).to receive(:receive_message).with(limit: 1).and_return([])
21
+ allow(sqs_queue).to receive(:receive_message).with(limit: 1, message_attribute_names: ['shoryuken_class']).and_return([])
22
22
 
23
23
  expect(manager).to receive(:pause_queue!).with(queue)
24
24
  expect(manager).to receive(:dispatch)
@@ -27,7 +27,7 @@ describe Shoryuken::Fetcher do
27
27
  end
28
28
 
29
29
  it 'assigns messages' do
30
- allow(sqs_queue).to receive(:receive_message).with(limit: 5).and_return(sqs_msg)
30
+ allow(sqs_queue).to receive(:receive_message).with(limit: 5, message_attribute_names: ['shoryuken_class']).and_return(sqs_msg)
31
31
 
32
32
  expect(manager).to receive(:rebalance_queue_weight!).with(queue)
33
33
  expect(manager).to receive(:assign).with(queue, sqs_msg)
@@ -39,7 +39,7 @@ describe Shoryuken::Fetcher do
39
39
  it 'assigns messages in batch' do
40
40
  TestWorker.get_shoryuken_options['batch'] = true
41
41
 
42
- allow(sqs_queue).to receive(:receive_message).with(limit: described_class::FETCH_LIMIT).and_return(sqs_msg)
42
+ allow(sqs_queue).to receive(:receive_message).with(limit: described_class::FETCH_LIMIT, message_attribute_names: ['shoryuken_class']).and_return(sqs_msg)
43
43
 
44
44
  expect(manager).to receive(:rebalance_queue_weight!).with(queue)
45
45
  expect(manager).to receive(:assign).with(queue, [sqs_msg])
@@ -47,5 +47,19 @@ describe Shoryuken::Fetcher do
47
47
 
48
48
  subject.fetch(queue, 5)
49
49
  end
50
+
51
+ context 'when worker not found' do
52
+ let(:queue) { 'notfound' }
53
+
54
+ it 'ignores batch' do
55
+ allow(sqs_queue).to receive(:receive_message).with(limit: 5, message_attribute_names: ['shoryuken_class']).and_return(sqs_msg)
56
+
57
+ expect(manager).to receive(:rebalance_queue_weight!).with(queue)
58
+ expect(manager).to receive(:assign).with(queue, sqs_msg)
59
+ expect(manager).to receive(:dispatch)
60
+
61
+ subject.fetch(queue, 5)
62
+ end
63
+ end
50
64
  end
51
65
  end
@@ -71,4 +71,37 @@ describe Shoryuken::Manager do
71
71
  expect(subject.instance_variable_get('@queues')).to eq [queue2, queue1]
72
72
  end
73
73
  end
74
+
75
+ describe '#next_queue' do
76
+ it 'returns queues' do
77
+ queue1 = 'shoryuken'
78
+ queue2 = 'uppercut'
79
+
80
+ Shoryuken.queues.clear
81
+
82
+ Shoryuken.register_worker queue1, TestWorker
83
+ Shoryuken.register_worker queue2, TestWorker
84
+
85
+ Shoryuken.queues << queue1
86
+ Shoryuken.queues << queue2
87
+
88
+ expect(subject.send :next_queue).to eq queue1
89
+ expect(subject.send :next_queue).to eq queue2
90
+ end
91
+
92
+ it 'skips when no worker' do
93
+ queue1 = 'shoryuken'
94
+ queue2 = 'uppercut'
95
+
96
+ Shoryuken.queues.clear
97
+
98
+ Shoryuken.register_worker queue2, TestWorker
99
+
100
+ Shoryuken.queues << queue1
101
+ Shoryuken.queues << queue2
102
+
103
+ expect(subject.send :next_queue).to eq queue2
104
+ expect(subject.send :next_queue).to eq queue2
105
+ end
106
+ end
74
107
  end
@@ -10,7 +10,7 @@ describe Shoryuken::Middleware::Server::AutoDelete do
10
10
  end
11
11
 
12
12
  it 'deletes a message' do
13
- TestWorker.get_shoryuken_options['delete'] = true
13
+ TestWorker.get_shoryuken_options['auto_delete'] = true
14
14
 
15
15
  expect(sqs_queue).to receive(:batch_delete).with(sqs_msg)
16
16
 
@@ -18,7 +18,7 @@ describe Shoryuken::Middleware::Server::AutoDelete do
18
18
  end
19
19
 
20
20
  it 'deletes a batch' do
21
- TestWorker.get_shoryuken_options['delete'] = true
21
+ TestWorker.get_shoryuken_options['auto_delete'] = true
22
22
 
23
23
  sqs_msg2 = double 'SQS msg', body: 'test'
24
24
  sqs_msg3 = double 'SQS msg', body: 'test'
@@ -31,7 +31,7 @@ describe Shoryuken::Middleware::Server::AutoDelete do
31
31
  end
32
32
 
33
33
  it 'does not delete a message' do
34
- TestWorker.get_shoryuken_options['delete'] = false
34
+ TestWorker.get_shoryuken_options['auto_delete'] = false
35
35
 
36
36
  expect(sqs_queue).to_not receive(:batch_delete)
37
37
 
@@ -6,7 +6,7 @@ describe Shoryuken::Processor do
6
6
  let(:manager) { double Shoryuken::Manager, processor_done: nil }
7
7
  let(:sqs_queue) { double AWS::SQS::Queue, visibility_timeout: 30 }
8
8
  let(:queue) { 'default' }
9
- let(:sqs_msg) { double AWS::SQS::ReceivedMessage, id: 'fc754df7-9cc2-4c41-96ca-5996a44b771e', body: 'test' }
9
+ let(:sqs_msg) { double AWS::SQS::ReceivedMessage, id: 'fc754df7-9cc2-4c41-96ca-5996a44b771e', body: 'test', message_attributes: {} }
10
10
 
11
11
  subject { described_class.new(manager) }
12
12
 
@@ -16,7 +16,7 @@ describe Shoryuken::Processor do
16
16
  end
17
17
 
18
18
  describe '#process' do
19
- it 'parses the body into JSON' do
19
+ it 'parsers the body into JSON' do
20
20
  TestWorker.get_shoryuken_options['body_parser'] = :json
21
21
 
22
22
  body = { 'test' => 'hi' }
@@ -28,7 +28,7 @@ describe Shoryuken::Processor do
28
28
  subject.process(queue, sqs_msg)
29
29
  end
30
30
 
31
- it 'parses the body calling the proc' do
31
+ it 'parsers the body calling the proc' do
32
32
  TestWorker.get_shoryuken_options['body_parser'] = Proc.new { |sqs_msg| "*#{sqs_msg.body}*" }
33
33
 
34
34
  expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, '*test*')
@@ -38,7 +38,7 @@ describe Shoryuken::Processor do
38
38
  subject.process(queue, sqs_msg)
39
39
  end
40
40
 
41
- it 'parses the body as text' do
41
+ it 'parsers the body as text' do
42
42
  TestWorker.get_shoryuken_options['body_parser'] = :text
43
43
 
44
44
  body = 'test'
@@ -50,7 +50,7 @@ describe Shoryuken::Processor do
50
50
  subject.process(queue, sqs_msg)
51
51
  end
52
52
 
53
- it 'parses calling `.parse`' do
53
+ it 'parsers calling `.parse`' do
54
54
  TestWorker.get_shoryuken_options['body_parser'] = JSON
55
55
 
56
56
  body = { 'test' => 'hi' }
@@ -77,7 +77,7 @@ describe Shoryuken::Processor do
77
77
  end
78
78
 
79
79
  context 'when `object_type: nil`' do
80
- it 'parses the body as text' do
80
+ it 'parsers the body as text' do
81
81
  TestWorker.get_shoryuken_options['body_parser'] = nil
82
82
 
83
83
  body = 'test'
@@ -126,7 +126,7 @@ describe Shoryuken::Processor do
126
126
  end
127
127
 
128
128
  it 'performs with delete' do
129
- TestWorker.get_shoryuken_options['delete'] = true
129
+ TestWorker.get_shoryuken_options['auto_delete'] = true
130
130
 
131
131
  expect(manager).to receive(:processor_done).with(queue, subject)
132
132
 
@@ -138,7 +138,7 @@ describe Shoryuken::Processor do
138
138
  end
139
139
 
140
140
  it 'performs without delete' do
141
- TestWorker.get_shoryuken_options['delete'] = false
141
+ TestWorker.get_shoryuken_options['auto_delete'] = false
142
142
 
143
143
  expect(manager).to receive(:processor_done).with(queue, subject)
144
144
 
@@ -148,5 +148,26 @@ describe Shoryuken::Processor do
148
148
 
149
149
  subject.process(queue, sqs_msg)
150
150
  end
151
+
152
+ context 'when shoryuken_class header' do
153
+ let(:sqs_msg) { double AWS::SQS::ReceivedMessage, id: 'fc754df7-9cc2-4c41-96ca-5996a44b771e', body: 'test', message_attributes: {
154
+ 'shoryuken_class' => {
155
+ string_value: TestWorker.to_s,
156
+ data_type: 'String'
157
+ }
158
+ } }
159
+
160
+ it 'performs without delete' do
161
+ Shoryuken.workers.clear # unregister TestWorker
162
+
163
+ expect(manager).to receive(:processor_done).with(queue, subject)
164
+
165
+ expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, sqs_msg.body)
166
+
167
+ expect(sqs_queue).to_not receive(:batch_delete)
168
+
169
+ subject.process(queue, sqs_msg)
170
+ end
171
+ end
151
172
  end
152
173
  end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoryuken::WorkerLoader do
4
+ let(:queue) { 'default' }
5
+ let(:sqs_msg) { double AWS::SQS::ReceivedMessage, id: 'fc754df7-9cc2-4c41-96ca-5996a44b771e', body: 'test', message_attributes: { } }
6
+
7
+ describe '.call' do
8
+ it 'returns the worker using `Shoryuken.workers`' do
9
+ expect(described_class.call(queue, sqs_msg)).to be_an_instance_of TestWorker
10
+ end
11
+
12
+ context 'when `message_attributes`' do
13
+ let(:sqs_msg) { double AWS::SQS::ReceivedMessage, id: 'fc754df7-9cc2-4c41-96ca-5996a44b771e', body: 'test', message_attributes: {
14
+ 'shoryuken_class' => {
15
+ string_value: TestWorker.to_s,
16
+ data_type: 'String'
17
+ }
18
+ } }
19
+
20
+ it 'returns the worker using `message_attributes`' do
21
+ Shoryuken.workers.clear
22
+
23
+ expect(described_class.call(queue, sqs_msg)).to be_an_instance_of TestWorker
24
+ end
25
+ end
26
+ end
27
+ end
@@ -8,15 +8,74 @@ describe 'Shoryuken::Worker' do
8
8
  allow(Shoryuken::Client).to receive(:queues).with(queue).and_return(sqs_queue)
9
9
  end
10
10
 
11
+ describe '.perform_in' do
12
+ it 'delays a message' do
13
+ expect(sqs_queue).to receive(:send_message).with('message', {
14
+ message_attributes: {
15
+ 'shoryuken_class' => {
16
+ string_value: TestWorker.to_s,
17
+ data_type: 'String'
18
+ }
19
+ },
20
+ delay_seconds: 60
21
+ })
22
+
23
+ TestWorker.perform_in(60, 'message')
24
+ end
25
+
26
+ it 'raises an exception' do
27
+ expect {
28
+ TestWorker.perform_in(901, 'message')
29
+ }.to raise_error 'The maximum allowed delay is 15 minutes'
30
+ end
31
+ end
32
+
33
+ describe '.perform_at' do
34
+ it 'delays a message' do
35
+ expect(sqs_queue).to receive(:send_message).with('message', {
36
+ message_attributes: {
37
+ 'shoryuken_class' => {
38
+ string_value: TestWorker.to_s,
39
+ data_type: 'String'
40
+ }
41
+ },
42
+ delay_seconds: 60
43
+ })
44
+
45
+ TestWorker.perform_in(Time.now + 60, 'message')
46
+ end
47
+
48
+ it 'raises an exception' do
49
+ expect {
50
+ TestWorker.perform_in(Time.now + 901, 'message')
51
+ }.to raise_error 'The maximum allowed delay is 15 minutes'
52
+ end
53
+ end
54
+
11
55
  describe '.perform_async' do
12
56
  it 'enqueues a message' do
13
- expect(sqs_queue).to receive(:send_message).with('message', {})
57
+ expect(sqs_queue).to receive(:send_message).with('message', {
58
+ message_attributes: {
59
+ 'shoryuken_class' => {
60
+ string_value: TestWorker.to_s,
61
+ data_type: 'String'
62
+ }
63
+ }
64
+ })
14
65
 
15
66
  TestWorker.perform_async('message')
16
67
  end
17
68
 
18
69
  it 'enqueues a message with options' do
19
- expect(sqs_queue).to receive(:send_message).with('delayed message', delay_seconds: 60)
70
+ expect(sqs_queue).to receive(:send_message).with('delayed message', {
71
+ delay_seconds: 60,
72
+ message_attributes: {
73
+ 'shoryuken_class' => {
74
+ string_value: TestWorker.to_s,
75
+ data_type: 'String'
76
+ }
77
+ }
78
+ })
20
79
 
21
80
  TestWorker.perform_async('delayed message', delay_seconds: 60)
22
81
  end
@@ -37,6 +96,7 @@ describe 'Shoryuken::Worker' do
37
96
  end
38
97
 
39
98
  expect(Shoryuken.workers['production_default']).to eq NewTestWorker
99
+ expect(NewTestWorker.get_shoryuken_options['queue']).to eq 'production_default'
40
100
  end
41
101
  end
42
102
  end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoryuken do
4
+ describe '.register_worker' do
5
+ it 'registers a worker' do
6
+ described_class.workers.clear
7
+ described_class.register_worker('default', TestWorker)
8
+ expect(described_class.workers).to eq('default' => TestWorker)
9
+ end
10
+
11
+ it 'registers a batchable worker' do
12
+ described_class.workers.clear
13
+ TestWorker.get_shoryuken_options['batch'] = true
14
+ described_class.register_worker('default', TestWorker)
15
+ expect(described_class.workers).to eq('default' => TestWorker)
16
+ end
17
+
18
+ it 'allows multiple workers' do
19
+ described_class.workers.clear
20
+ described_class.register_worker('default', TestWorker)
21
+ expect(described_class.workers).to eq('default' => TestWorker)
22
+
23
+ class Test2Worker
24
+ include Shoryuken::Worker
25
+
26
+ shoryuken_options queue: 'default'
27
+
28
+ def perform(sqs_msg, body); end
29
+ end
30
+
31
+ expect(described_class.workers).to eq('default' => Test2Worker)
32
+ end
33
+
34
+ it 'raises an exception when mixing batchable with non batchable' do
35
+ described_class.workers.clear
36
+ TestWorker.get_shoryuken_options['batch'] = true
37
+ described_class.register_worker('default', TestWorker)
38
+
39
+ expect {
40
+ class BatchableWorker
41
+ include Shoryuken::Worker
42
+
43
+ shoryuken_options queue: 'default', batch: true
44
+
45
+ def perform(sqs_msg, body); end
46
+ end
47
+ }.to raise_error("Could not register BatchableWorker for 'default', because TestWorker is already registered for this queue, " \
48
+ "and Shoryuken doesn't support a batchable worker for a queue with multiple workers")
49
+ end
50
+ end
51
+ end
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,7 @@ Bundler.setup
4
4
  require 'pry-byebug'
5
5
  require 'celluloid'
6
6
  require 'shoryuken'
7
+ require 'json'
7
8
 
8
9
  options_file = File.join(File.expand_path('../..', __FILE__), 'shoryuken.yml')
9
10
 
@@ -40,7 +41,7 @@ RSpec.configure do |config|
40
41
  Shoryuken.options.merge!($options)
41
42
 
42
43
  Shoryuken.queues.clear
43
- Shoryuken.queues << 'shoryuken'
44
+
44
45
  Shoryuken.options[:concurrency] = 1
45
46
  Shoryuken.options[:delay] = 1
46
47
  Shoryuken.options[:timeout] = 1
@@ -49,5 +50,8 @@ RSpec.configure do |config|
49
50
 
50
51
  TestWorker.get_shoryuken_options.clear
51
52
  TestWorker.get_shoryuken_options['queue'] = 'default'
53
+
54
+ Shoryuken.workers.clear
55
+ Shoryuken.register_worker('default', TestWorker)
52
56
  end
53
57
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shoryuken
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pablo Cantero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-26 00:00:00.000000000 Z
11
+ date: 2014-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: aws-sdk
70
+ name: aws-sdk-v1
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '>='
@@ -84,16 +84,16 @@ dependencies:
84
84
  name: celluloid
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ~>
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 0.15.2
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ~>
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: 0.15.2
97
97
  description: Shoryuken is a super efficient AWS SQS thread based message processor
98
98
  email:
99
99
  - pablo@pablocantero.com
@@ -110,10 +110,8 @@ files:
110
110
  - README.md
111
111
  - Rakefile
112
112
  - bin/shoryuken
113
- - examples/all.rb
113
+ - examples/bootstrap_queues.rb
114
114
  - examples/default_worker.rb
115
- - examples/high_priority_worker.rb
116
- - examples/low_priority_worker.rb
117
115
  - lib/shoryuken.rb
118
116
  - lib/shoryuken/cli.rb
119
117
  - lib/shoryuken/client.rb
@@ -123,12 +121,14 @@ files:
123
121
  - lib/shoryuken/logging.rb
124
122
  - lib/shoryuken/manager.rb
125
123
  - lib/shoryuken/middleware/chain.rb
124
+ - lib/shoryuken/middleware/server/active_record.rb
126
125
  - lib/shoryuken/middleware/server/auto_delete.rb
127
126
  - lib/shoryuken/middleware/server/timing.rb
128
127
  - lib/shoryuken/processor.rb
129
128
  - lib/shoryuken/util.rb
130
129
  - lib/shoryuken/version.rb
131
130
  - lib/shoryuken/worker.rb
131
+ - lib/shoryuken/worker_loader.rb
132
132
  - shoryuken.gemspec
133
133
  - shoryuken.jpg
134
134
  - spec/integration/launcher_spec.rb
@@ -141,7 +141,9 @@ files:
141
141
  - spec/shoryuken/middleware/server/timing_spec.rb
142
142
  - spec/shoryuken/processor_spec.rb
143
143
  - spec/shoryuken/util_spec.rb
144
+ - spec/shoryuken/worker_loader_spec.rb
144
145
  - spec/shoryuken/worker_spec.rb
146
+ - spec/shoryuken_spec.rb
145
147
  - spec/spec_helper.rb
146
148
  homepage: https://github.com/phstc/shoryuken
147
149
  licenses:
@@ -178,5 +180,7 @@ test_files:
178
180
  - spec/shoryuken/middleware/server/timing_spec.rb
179
181
  - spec/shoryuken/processor_spec.rb
180
182
  - spec/shoryuken/util_spec.rb
183
+ - spec/shoryuken/worker_loader_spec.rb
181
184
  - spec/shoryuken/worker_spec.rb
185
+ - spec/shoryuken_spec.rb
182
186
  - spec/spec_helper.rb
data/examples/all.rb DELETED
@@ -1,5 +0,0 @@
1
- $stdout.sync = true
2
-
3
- require_relative 'high_priority_worker'
4
- require_relative 'default_worker'
5
- require_relative 'low_priority_worker'
@@ -1,9 +0,0 @@
1
- class HighPriorityWorker
2
- include Shoryuken::Worker
3
-
4
- shoryuken_options queue: 'high_priority', delete: true
5
-
6
- def perform(sqs_msg, body)
7
- puts "HighPriorityWorker: '#{body}'"
8
- end
9
- end
@@ -1,11 +0,0 @@
1
- class LowPriorityWorker
2
- include Shoryuken::Worker
3
-
4
- shoryuken_options queue: 'low_priority', delete: true, batch: true
5
-
6
- def perform(sqs_msgs, bodies)
7
- bodies.each_with_index do |body, index|
8
- puts "LowPriorityWorker (#{index}): '#{body}'"
9
- end
10
- end
11
- end