shoryuken 3.1.3 → 3.2.0

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +13 -3
  4. data/CHANGELOG.md +68 -0
  5. data/Gemfile +5 -3
  6. data/Gemfile.aws-sdk-core-v2 +13 -0
  7. data/bin/cli/sqs.rb +8 -4
  8. data/bin/shoryuken +2 -1
  9. data/lib/shoryuken/body_parser.rb +27 -0
  10. data/lib/shoryuken/fetcher.rb +40 -13
  11. data/lib/shoryuken/launcher.rb +2 -17
  12. data/lib/shoryuken/manager.rb +17 -5
  13. data/lib/shoryuken/middleware/chain.rb +4 -0
  14. data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +2 -5
  15. data/lib/shoryuken/middleware/server/timing.rb +12 -14
  16. data/lib/shoryuken/options.rb +21 -1
  17. data/lib/shoryuken/processor.rb +5 -21
  18. data/lib/shoryuken/queue.rb +12 -5
  19. data/lib/shoryuken/runner.rb +3 -1
  20. data/lib/shoryuken/util.rb +2 -2
  21. data/lib/shoryuken/version.rb +1 -1
  22. data/lib/shoryuken/worker/default_executor.rb +33 -0
  23. data/lib/shoryuken/worker/inline_executor.rb +28 -0
  24. data/lib/shoryuken/worker.rb +68 -31
  25. data/lib/shoryuken.rb +12 -0
  26. data/shoryuken.gemspec +1 -1
  27. data/spec/shoryuken/body_parser_spec.rb +89 -0
  28. data/spec/shoryuken/fetcher_spec.rb +61 -9
  29. data/spec/shoryuken/manager_spec.rb +2 -2
  30. data/spec/shoryuken/middleware/chain_spec.rb +16 -4
  31. data/spec/shoryuken/options_spec.rb +80 -0
  32. data/spec/shoryuken/processor_spec.rb +15 -97
  33. data/spec/shoryuken/queue_spec.rb +43 -32
  34. data/spec/shoryuken/util_spec.rb +25 -1
  35. data/spec/shoryuken/worker/default_executor_spec.rb +100 -0
  36. data/spec/shoryuken/worker/inline_executor_spec.rb +23 -0
  37. data/spec/shoryuken/worker_spec.rb +32 -91
  38. data/spec/spec_helper.rb +2 -0
  39. metadata +15 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 942ccdeaca0a94e766b82fa40da9ed091b703ea2
4
- data.tar.gz: f94a089b56ed37b5db2752ccf418c667fae31b6d
3
+ metadata.gz: f74e5fbb599fe5bbe41bed5fd542c0c1fdcc2d35
4
+ data.tar.gz: 6099d42682b5e2a1797d7cdbdc7bf27b344b692c
5
5
  SHA512:
6
- metadata.gz: 67c92d3af6c4063f42afe07a3f56c32b847bd1bc76d80f4f9f46cc2aa48d3e7bf82213f4d98fe229265ce9b1387a3649652863f019e73aeb0d809b1a03c5ca4d
7
- data.tar.gz: 1215eca9e669975edb70fa43855122e6f25c6e54452771ba26435f7e8df37684be20516037e1419a3e7d93a14773231387f471cc2ff8a03eb838f1e52f2c144d
6
+ metadata.gz: f076e8f427f39ca92be4f27be819350d90270ce9e695d1173a6944b82d16680d11afd78a0075dd549e0a2c6031e6d5708c306cb245c4d7dfcc69d8a5e7151bc7
7
+ data.tar.gz: 2fd34c84e6260df3c35427ffb27d3d067fc1ea11469609d61e8eedd465e4516d75e052079b5195ede7c7917ad3c97bb39c5440bc5436ae3ab2581f3fb72bad31
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.0
2
+ TargetRubyVersion: 2.1
3
3
 
4
4
  Style/SignalException:
5
5
  Enabled: false
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
+
2
3
  rvm:
3
4
  - 2.0.0
4
- - 2.1.0
5
+ - 2.1.10
5
6
  - 2.2.0
6
7
  - 2.3.3
7
8
  - 2.4.1
@@ -11,9 +12,18 @@ notifications:
11
12
  on_success: change
12
13
  on_failure: always
13
14
 
14
- script: SPEC_ALL=true bundle exec rspec spec
15
+ gemfile:
16
+ - Gemfile
17
+ - Gemfile.aws-sdk-core-v2
18
+
19
+ env:
20
+ - SPEC_ALL=true
21
+
22
+ script: bundle exec rspec spec
23
+
15
24
  before_install:
16
- - gem update bundler
25
+ - gem update bundler
26
+
17
27
  after_success:
18
28
  - bundle exec codeclimate-test-reporter
19
29
 
data/CHANGELOG.md CHANGED
@@ -1,3 +1,71 @@
1
+ ## [v3.2.0] - 2018-01-03
2
+
3
+ - Preserve parent worker class options
4
+ - [#451](https://github.com/phstc/shoryuken/pull/451)
5
+
6
+ - Add -t (shutdown timeout) option to CL
7
+ - [#449](https://github.com/phstc/shoryuken/pull/449)
8
+
9
+ - Support inline (Active Job like) for standard workers
10
+ - [#448](https://github.com/phstc/shoryuken/pull/448)
11
+
12
+ ## [v3.1.12] - 2017-09-25
13
+
14
+ - Reduce fetch log verbosity
15
+ - [#436](https://github.com/phstc/shoryuken/pull/436)
16
+
17
+ ## [v3.1.11] - 2017-09-02
18
+
19
+ - Auto retry (up to 3 times) fetch errors
20
+ - [#429](https://github.com/phstc/shoryuken/pull/429)
21
+
22
+ ## [v3.1.10] - 2017-09-02
23
+
24
+ - Make Shoryuken compatible with AWS SDK 3 and 2
25
+ - [#433](https://github.com/phstc/shoryuken/pull/433)
26
+
27
+ ## [v3.1.9] - 2017-08-24
28
+
29
+ - Add support for adding a middleware to the front of chain
30
+ - [#427](https://github.com/phstc/shoryuken/pull/427)
31
+
32
+ - Add support for dispatch fire event
33
+ - [#426](https://github.com/phstc/shoryuken/pull/426)
34
+
35
+ ## [v3.1.8] - 2017-08-17
36
+
37
+ - Make Polling strategy backward compatibility
38
+ - [#424](https://github.com/phstc/shoryuken/pull/424)
39
+
40
+ ## [v3.1.7] - 2017-07-31
41
+
42
+ - Allow polling strategy per group
43
+ - [#417](https://github.com/phstc/shoryuken/pull/417)
44
+
45
+ - Add support for creating FIFO queues
46
+ - [#419](https://github.com/phstc/shoryuken/pull/419)
47
+
48
+ - Allow receive message options per queue
49
+ - [#420](https://github.com/phstc/shoryuken/pull/420)
50
+
51
+ ## [v3.1.6] - 2017-07-24
52
+
53
+ - Fix issue with dispatch_loop and delays
54
+ - [#416](https://github.com/phstc/shoryuken/pull/416)
55
+
56
+ ## [v3.1.5] - 2017-07-23
57
+
58
+ - Fix memory leak
59
+ - [#414](https://github.com/phstc/shoryuken/pull/414)
60
+
61
+ - Fail fast on bad queue URLs
62
+ - [#413](https://github.com/phstc/shoryuken/pull/413)
63
+
64
+ ## [v3.1.4] - 2017-07-14
65
+
66
+ - Require forwardable allowding to call `shoryuken` without `bundle exec`
67
+ - [#409](https://github.com/phstc/shoryuken/pull/409)
68
+
1
69
  ## [v3.1.3] - 2017-07-11
2
70
 
3
71
  - Add queue prefixing support for groups
data/Gemfile CHANGED
@@ -4,9 +4,11 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :test do
7
- gem 'activejob'
7
+ gem 'activejob', '~> 4'
8
+ gem 'aws-sdk-core', '~> 3'
9
+ gem 'aws-sdk-sqs'
8
10
  gem 'codeclimate-test-reporter', require: nil
9
- gem 'simplecov'
10
- gem 'multi_xml'
11
11
  gem 'httparty'
12
+ gem 'multi_xml'
13
+ gem 'simplecov'
12
14
  end
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in shoryuken.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'activejob', '~> 4'
8
+ gem 'aws-sdk-core', '~> 2'
9
+ gem 'codeclimate-test-reporter', require: nil
10
+ gem 'httparty'
11
+ gem 'multi_xml'
12
+ gem 'simplecov'
13
+ end
data/bin/cli/sqs.rb CHANGED
@@ -96,8 +96,8 @@ module Shoryuken
96
96
  end
97
97
 
98
98
  desc 'ls [QUEUE-NAME-PREFIX]', 'Lists queues'
99
- method_option :watch, aliases: '-w', type: :boolean, desc: 'watch queues'
100
- method_option :watch_interval, type: :numeric, default: 10, desc: 'watch interval'
99
+ method_option :watch, aliases: '-w', type: :boolean, desc: 'watch queues'
100
+ method_option :interval, aliases: '-n', type: :numeric, default: 2, desc: 'watch interval in seconds'
101
101
  def ls(queue_name_prefix = '')
102
102
  trap('SIGINT', 'EXIT') # expect ctrl-c from loop
103
103
 
@@ -108,7 +108,7 @@ module Shoryuken
108
108
 
109
109
  break unless options[:watch]
110
110
 
111
- sleep options[:watch_interval]
111
+ sleep options[:interval]
112
112
  puts
113
113
  end
114
114
  end
@@ -187,8 +187,12 @@ module Shoryuken
187
187
  end
188
188
 
189
189
  desc 'create QUEUE-NAME', 'Create a queue'
190
+ method_option :attributes, aliases: '-a', type: :hash, default: {}, desc: 'queue attributes'
190
191
  def create(queue_name)
191
- queue_url = sqs.create_queue(queue_name: queue_name).queue_url
192
+ attributes = options[:attributes]
193
+ attributes['FifoQueue'] ||= 'true' if queue_name.end_with?('.fifo')
194
+
195
+ queue_url = sqs.create_queue(queue_name: queue_name, attributes: attributes).queue_url
192
196
 
193
197
  say "Queue #{queue_name} was successfully created. Queue URL #{queue_url}", :green
194
198
  end
data/bin/shoryuken CHANGED
@@ -21,6 +21,7 @@ module Shoryuken
21
21
  method_option :daemon, aliases: '-d', type: :boolean, desc: 'Daemonize process'
22
22
  method_option :queues, aliases: '-q', type: :array, desc: 'Queues to process with optional weights'
23
23
  method_option :require, aliases: '-r', type: :string, desc: 'Dir or path of the workers'
24
+ method_option :timeout, aliases: '-t', type: :numeric, desc: 'Hard shutdown timeout'
24
25
  method_option :config, aliases: '-C', type: :string, desc: 'Path to config file'
25
26
  method_option :config_file, type: :string, desc: 'Path to config file (backwards compatibility)'
26
27
  method_option :rails, aliases: '-R', type: :boolean, desc: 'Load Rails'
@@ -32,7 +33,7 @@ module Shoryuken
32
33
  opts = options.to_h.symbolize_keys
33
34
 
34
35
  if opts[:config_file]
35
- say "[DEPRECATED] Please use --config instead of --config-file", :yellow
36
+ say '[DEPRECATED] Please use --config instead of --config-file', :yellow
36
37
  end
37
38
 
38
39
  opts[:config_file] = opts.delete(:config) if opts[:config]
@@ -0,0 +1,27 @@
1
+ module Shoryuken
2
+ class BodyParser
3
+ class << self
4
+ def parse(worker_class, sqs_msg)
5
+ body_parser = worker_class.get_shoryuken_options['body_parser']
6
+
7
+ case body_parser
8
+ when :json
9
+ JSON.parse(sqs_msg.body)
10
+ when Proc
11
+ body_parser.call(sqs_msg)
12
+ when :text, nil
13
+ sqs_msg.body
14
+ else
15
+ if body_parser.respond_to?(:parse)
16
+ # JSON.parse
17
+ body_parser.parse(sqs_msg.body)
18
+ elsif body_parser.respond_to?(:load)
19
+ # see https://github.com/phstc/shoryuken/pull/91
20
+ # JSON.load
21
+ body_parser.load(sqs_msg.body)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -4,34 +4,50 @@ module Shoryuken
4
4
 
5
5
  FETCH_LIMIT = 10
6
6
 
7
- attr_reader :group
8
-
9
7
  def initialize(group)
10
8
  @group = group
11
9
  end
12
10
 
13
11
  def fetch(queue, limit)
14
- started_at = Time.now
12
+ fetch_with_auto_retry(3) do
13
+ started_at = Time.now
15
14
 
16
- logger.debug { "Looking for new messages in #{queue}" }
15
+ logger.debug { "Looking for new messages in #{queue}" }
17
16
 
18
- sqs_msgs = Array(receive_messages(queue, [FETCH_LIMIT, limit].min))
17
+ sqs_msgs = Array(receive_messages(queue, [FETCH_LIMIT, limit].min))
19
18
 
20
- logger.info { "Found #{sqs_msgs.size} messages for #{queue.name}" } unless sqs_msgs.empty?
21
- logger.debug { "Fetcher for #{queue} completed in #{elapsed(started_at)} ms" }
19
+ logger.debug { "Found #{sqs_msgs.size} messages for #{queue.name}" } unless sqs_msgs.empty?
20
+ logger.debug { "Fetcher for #{queue} completed in #{elapsed(started_at)} ms" }
22
21
 
23
- sqs_msgs
22
+ sqs_msgs
23
+ end
24
24
  end
25
25
 
26
26
  private
27
27
 
28
- def receive_messages(queue, limit)
29
- # AWS limits the batch size by 10
30
- limit = limit > FETCH_LIMIT ? FETCH_LIMIT : limit
28
+ def fetch_with_auto_retry(max_attempts, &block)
29
+ attempts = 0
30
+
31
+ begin
32
+ yield
33
+ rescue => ex
34
+ # Tries to auto retry connectivity errors
35
+ raise if attempts >= max_attempts
36
+
37
+ attempts += 1
38
+
39
+ logger.debug { "Retrying fetch attempt #{attempts} for #{ex.message}" }
40
+
41
+ sleep((1..5).to_a.sample)
42
+
43
+ retry
44
+ end
45
+ end
31
46
 
32
- options = Shoryuken.sqs_client_receive_message_opts[group].to_h.dup
47
+ def receive_messages(queue, limit)
48
+ options = receive_options(queue)
33
49
 
34
- options[:max_number_of_messages] = limit
50
+ options[:max_number_of_messages] = max_number_of_messages(limit, options)
35
51
  options[:message_attribute_names] = %w(All)
36
52
  options[:attribute_names] = %w(All)
37
53
 
@@ -39,5 +55,16 @@ module Shoryuken
39
55
 
40
56
  Shoryuken::Client.queues(queue.name).receive_messages(options)
41
57
  end
58
+
59
+ def max_number_of_messages(limit, options)
60
+ [limit, FETCH_LIMIT, options[:max_number_of_messages]].compact.min
61
+ end
62
+
63
+ def receive_options(queue)
64
+ options = Shoryuken.sqs_client_receive_message_opts[queue.name]
65
+ options ||= Shoryuken.sqs_client_receive_message_opts[@group]
66
+
67
+ options.to_h.dup
68
+ end
42
69
  end
43
70
  end
@@ -3,8 +3,7 @@ module Shoryuken
3
3
  include Util
4
4
 
5
5
  def initialize
6
- @managers = create_managers
7
- @shutdowning = Concurrent::AtomicBoolean.new(false)
6
+ @managers = create_managers
8
7
  end
9
8
 
10
9
  def start
@@ -41,24 +40,10 @@ module Shoryuken
41
40
 
42
41
  def start_managers
43
42
  @managers.each do |manager|
44
- Concurrent::Promise.execute { manager.start }.rescue do |ex|
45
- log_manager_failure(ex)
46
- start_soft_shutdown
47
- end
43
+ Concurrent::Future.execute { manager.start }
48
44
  end
49
45
  end
50
46
 
51
- def start_soft_shutdown
52
- Process.kill('USR1', Process.pid) if @shutdowning.make_true
53
- end
54
-
55
- def log_manager_failure(ex)
56
- return unless ex
57
-
58
- logger.error { "Manager failed: #{ex.message}" }
59
- logger.error { ex.backtrace.join("\n") } unless ex.backtrace.nil?
60
- end
61
-
62
47
  def initiate_stop
63
48
  logger.info { 'Shutting down' }
64
49
 
@@ -12,6 +12,7 @@ module Shoryuken
12
12
  @max_processors = concurrency
13
13
  @busy_processors = Concurrent::AtomicFixnum.new(0)
14
14
  @executor = executor
15
+ @running = Concurrent::AtomicBoolean.new(true)
15
16
  end
16
17
 
17
18
  def start
@@ -21,15 +22,13 @@ module Shoryuken
21
22
  private
22
23
 
23
24
  def running?
24
- @executor.running?
25
+ @running.true? && @executor.running?
25
26
  end
26
27
 
27
28
  def dispatch_loop
28
29
  return unless running?
29
30
 
30
- Concurrent::Promise.execute(
31
- executor: @executor
32
- ) { dispatch }.then { dispatch_loop }.rescue { |ex| raise ex }
31
+ @executor.post { dispatch }
33
32
  end
34
33
 
35
34
  def dispatch
@@ -39,11 +38,15 @@ module Shoryuken
39
38
  return sleep(MIN_DISPATCH_INTERVAL)
40
39
  end
41
40
 
42
- fire_event(:dispatch)
41
+ fire_event(:dispatch, false, queue_name: queue.name)
43
42
 
44
43
  logger.debug { "Ready: #{ready}, Busy: #{busy}, Active Queues: #{@polling_strategy.active_queues}" }
45
44
 
46
45
  batched_queue?(queue) ? dispatch_batch(queue) : dispatch_single_messages(queue)
46
+ rescue => ex
47
+ handle_dispatch_error(ex)
48
+ ensure
49
+ dispatch_loop
47
50
  end
48
51
 
49
52
  def busy
@@ -96,5 +99,14 @@ module Shoryuken
96
99
 
97
100
  sqs_msgs
98
101
  end
102
+
103
+ def handle_dispatch_error(ex)
104
+ logger.error { "Manager failed: #{ex.message}" }
105
+ logger.error { ex.backtrace.join("\n") } unless ex.backtrace.nil?
106
+
107
+ Process.kill('USR1', Process.pid)
108
+
109
+ @running.make_false
110
+ end
99
111
  end
100
112
  end
@@ -61,6 +61,10 @@ module Shoryuken
61
61
  entries << Entry.new(klass, *args) unless exists?(klass)
62
62
  end
63
63
 
64
+ def prepend(klass, *args)
65
+ entries.insert(0, Entry.new(klass, *args)) unless exists?(klass)
66
+ end
67
+
64
68
  def insert_before(oldklass, newklass, *args)
65
69
  i = entries.index { |entry| entry.klass == newklass }
66
70
  new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
@@ -31,16 +31,13 @@ module Shoryuken
31
31
  Concurrent::TimerTask.new(execution_interval: queue_visibility_timeout - EXTEND_UPFRONT_SECONDS) do
32
32
  begin
33
33
  logger.debug do
34
- "Extending message #{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id} " \
35
- "visibility timeout by #{queue_visibility_timeout}s."
34
+ "Extending message #{queue}/#{sqs_msg.message_id} visibility timeout by #{queue_visibility_timeout}s"
36
35
  end
37
36
 
38
37
  sqs_msg.change_visibility(visibility_timeout: queue_visibility_timeout)
39
38
  rescue => ex
40
39
  logger.error do
41
- 'Could not auto extend the message ' \
42
- "#{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id} " \
43
- "visibility timeout. Error: #{ex.message}"
40
+ "Could not auto extend the message #{queue}/#{sqs_msg.message_id} visibility timeout. Error: #{ex.message}"
44
41
  end
45
42
  end
46
43
  end
@@ -5,25 +5,23 @@ module Shoryuken
5
5
  include Util
6
6
 
7
7
  def call(worker, queue, sqs_msg, body)
8
- Shoryuken::Logging.with_context("#{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id}") do
9
- begin
10
- started_at = Time.now
8
+ begin
9
+ started_at = Time.now
11
10
 
12
- logger.info { "started at #{started_at}" }
11
+ logger.info { "started at #{started_at}" }
13
12
 
14
- yield
13
+ yield
15
14
 
16
- total_time = elapsed(started_at)
15
+ total_time = elapsed(started_at)
17
16
 
18
- if (total_time / 1000.0) > (timeout = Shoryuken::Client.queues(queue).visibility_timeout)
19
- logger.warn { "exceeded the queue visibility timeout by #{total_time - (timeout * 1000)} ms" }
20
- end
21
-
22
- logger.info { "completed in: #{total_time} ms" }
23
- rescue
24
- logger.info { "failed in: #{elapsed(started_at)} ms" }
25
- raise
17
+ if (total_time / 1000.0) > (timeout = Shoryuken::Client.queues(queue).visibility_timeout)
18
+ logger.warn { "exceeded the queue visibility timeout by #{total_time - (timeout * 1000)} ms" }
26
19
  end
20
+
21
+ logger.info { "completed in: #{total_time} ms" }
22
+ rescue
23
+ logger.info { "failed in: #{elapsed(started_at)} ms" }
24
+ raise
27
25
  end
28
26
  end
29
27
  end
@@ -21,6 +21,7 @@ module Shoryuken
21
21
  @@sqs_client_receive_message_opts = {}
22
22
  @@start_callback = nil
23
23
  @@stop_callback = nil
24
+ @@worker_executor = Worker::DefaultExecutor
24
25
 
25
26
  class << self
26
27
  def active_job?
@@ -56,8 +57,27 @@ module Shoryuken
56
57
  @@worker_registry = worker_registry
57
58
  end
58
59
 
60
+ def worker_executor
61
+ @@worker_executor
62
+ end
63
+
64
+ def worker_executor=(worker_executor)
65
+ @@worker_executor = worker_executor
66
+ end
67
+
59
68
  def polling_strategy(group)
60
- options[group].to_h.fetch(:polling_strategy, Polling::WeightedRoundRobin)
69
+ strategy = (group == 'default' ? options : options[:groups].to_h[group]).to_h[:polling_strategy]
70
+
71
+ case strategy
72
+ when 'WeightedRoundRobin', nil # Default case
73
+ Polling::WeightedRoundRobin
74
+ when 'StrictPriority'
75
+ Polling::StrictPriority
76
+ when Class
77
+ strategy
78
+ else
79
+ raise ArgumentError, "#{strategy} is not a valid polling_strategy"
80
+ end
61
81
  end
62
82
 
63
83
  def start_callback
@@ -16,8 +16,10 @@ module Shoryuken
16
16
  def process
17
17
  return logger.error { "No worker found for #{queue}" } unless worker
18
18
 
19
- worker.class.server_middleware.invoke(worker, queue, sqs_msg, body) do
20
- worker.perform(sqs_msg, body)
19
+ Shoryuken::Logging.with_context("#{worker_name(worker.class, sqs_msg, body)}/#{queue}/#{sqs_msg.message_id}") do
20
+ worker.class.server_middleware.invoke(worker, queue, sqs_msg, body) do
21
+ worker.perform(sqs_msg, body)
22
+ end
21
23
  end
22
24
  rescue Exception => ex
23
25
  logger.error { "Processor failed: #{ex.message}" }
@@ -41,25 +43,7 @@ module Shoryuken
41
43
  end
42
44
 
43
45
  def parse_body(sqs_msg)
44
- body_parser = worker_class.get_shoryuken_options['body_parser']
45
-
46
- case body_parser
47
- when :json
48
- JSON.parse(sqs_msg.body)
49
- when Proc
50
- body_parser.call(sqs_msg)
51
- when :text, nil
52
- sqs_msg.body
53
- else
54
- if body_parser.respond_to?(:parse)
55
- # JSON.parse
56
- body_parser.parse(sqs_msg.body)
57
- elsif body_parser.respond_to?(:load)
58
- # see https://github.com/phstc/shoryuken/pull/91
59
- # JSON.load
60
- body_parser.load(sqs_msg.body)
61
- end
62
- end
46
+ BodyParser.parse(worker_class, sqs_msg)
63
47
  end
64
48
  end
65
49
  end
@@ -49,20 +49,27 @@ module Shoryuken
49
49
 
50
50
  private
51
51
 
52
- def set_name(name)
52
+ def set_by_name(name)
53
53
  self.name = name
54
54
  self.url = client.get_queue_url(queue_name: name).queue_url
55
- rescue Aws::Errors::NoSuchEndpointError, Aws::SQS::Errors::NonExistentQueue => ex
56
- raise ex, "The specified queue #{name} does not exist."
57
55
  end
58
56
 
59
- def set_url(url)
57
+ def set_by_url(url)
60
58
  self.name = url.split('/').last
61
59
  self.url = url
62
60
  end
63
61
 
64
62
  def set_name_and_url(name_or_url)
65
- name_or_url.start_with?('https://sqs.') ? set_url(name_or_url) : set_name(name_or_url)
63
+ if name_or_url.start_with?('https://sqs.')
64
+ set_by_url(name_or_url)
65
+
66
+ # anticipate the fifo? checker for validating the queue URL
67
+ return fifo?
68
+ end
69
+
70
+ set_by_name(name_or_url)
71
+ rescue Aws::Errors::NoSuchEndpointError, Aws::SQS::Errors::NonExistentQueue => ex
72
+ raise ex, "The specified queue #{name_or_url} does not exist."
66
73
  end
67
74
 
68
75
  def queue_attributes
@@ -118,10 +118,12 @@ module Shoryuken
118
118
  end
119
119
 
120
120
  def handle_signal(sig)
121
+ logger.debug "Got #{sig} signal"
122
+
121
123
  case sig
122
124
  when 'USR1' then execute_soft_shutdown
123
125
  when 'TTIN' then print_threads_backtrace
124
- else
126
+ when 'TERM', 'INT'
125
127
  logger.info { "Received #{sig}, will shutdown down" }
126
128
 
127
129
  raise Interrupt
@@ -4,13 +4,13 @@ module Shoryuken
4
4
  Shoryuken.logger
5
5
  end
6
6
 
7
- def fire_event(event, reverse = false)
7
+ def fire_event(event, reverse = false, event_options = {})
8
8
  logger.debug { "Firing '#{event}' lifecycle event" }
9
9
  arr = Shoryuken.options[:lifecycle_events][event]
10
10
  arr.reverse! if reverse
11
11
  arr.each do |block|
12
12
  begin
13
- block.call
13
+ block.call(event_options)
14
14
  rescue => ex
15
15
  logger.warn(event: event)
16
16
  logger.warn "#{ex.class.name}: #{ex.message}"
@@ -1,3 +1,3 @@
1
1
  module Shoryuken
2
- VERSION = '3.1.3'.freeze
2
+ VERSION = '3.2.0'.freeze
3
3
  end
@@ -0,0 +1,33 @@
1
+ module Shoryuken
2
+ module Worker
3
+ class DefaultExecutor
4
+ class << self
5
+ def perform_async(worker_class, body, options = {})
6
+ options[:message_attributes] ||= {}
7
+ options[:message_attributes]['shoryuken_class'] = {
8
+ string_value: worker_class.to_s,
9
+ data_type: 'String'
10
+ }
11
+
12
+ options[:message_body] = body
13
+
14
+ queue = options.delete(:queue) || worker_class.get_shoryuken_options['queue']
15
+
16
+ Shoryuken::Client.queues(queue).send_message(options)
17
+ end
18
+
19
+ def perform_in(worker_class, 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
+ worker_class.perform_async(body, options.merge(delay_seconds: delay))
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end