shoryuken 3.0.6 → 4.0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +90 -24
- data/.travis.yml +17 -5
- data/CHANGELOG.md +265 -62
- data/Gemfile +9 -1
- data/Gemfile.aws-sdk-core-v2 +13 -0
- data/README.md +19 -113
- data/Rakefile +1 -1
- data/bin/cli/base.rb +0 -3
- data/bin/cli/sqs.rb +42 -16
- data/bin/shoryuken +4 -9
- data/examples/bootstrap_queues.rb +3 -3
- data/examples/default_worker.rb +2 -2
- data/lib/shoryuken/body_parser.rb +27 -0
- data/lib/shoryuken/client.rb +6 -2
- data/lib/shoryuken/core_ext.rb +1 -1
- data/lib/shoryuken/default_worker_registry.rb +2 -2
- data/lib/shoryuken/environment_loader.rb +60 -24
- data/lib/shoryuken/extensions/active_job_adapter.rb +21 -11
- data/lib/shoryuken/fetcher.rb +58 -19
- data/lib/shoryuken/launcher.rb +70 -7
- data/lib/shoryuken/logging.rb +1 -6
- data/lib/shoryuken/manager.rb +50 -80
- data/lib/shoryuken/middleware/chain.rb +4 -0
- data/lib/shoryuken/middleware/server/active_record.rb +1 -1
- data/lib/shoryuken/middleware/server/auto_delete.rb +4 -9
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +6 -9
- data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +9 -3
- data/lib/shoryuken/middleware/server/timing.rb +12 -16
- data/lib/shoryuken/options.rb +225 -0
- data/lib/shoryuken/polling/base.rb +67 -0
- data/lib/shoryuken/polling/strict_priority.rb +77 -0
- data/lib/shoryuken/polling/weighted_round_robin.rb +66 -0
- data/lib/shoryuken/processor.rb +30 -39
- data/lib/shoryuken/queue.rb +41 -10
- data/lib/shoryuken/runner.rb +13 -17
- data/lib/shoryuken/util.rb +3 -3
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken/worker/default_executor.rb +33 -0
- data/lib/shoryuken/worker/inline_executor.rb +37 -0
- data/lib/shoryuken/worker.rb +76 -31
- data/lib/shoryuken/worker_registry.rb +4 -4
- data/lib/shoryuken.rb +54 -173
- data/shoryuken.gemspec +6 -6
- data/spec/integration/launcher_spec.rb +14 -8
- data/spec/shoryuken/body_parser_spec.rb +89 -0
- data/spec/shoryuken/client_spec.rb +1 -1
- data/spec/shoryuken/core_ext_spec.rb +6 -6
- data/spec/shoryuken/default_worker_registry_spec.rb +2 -4
- data/spec/shoryuken/environment_loader_spec.rb +32 -12
- data/spec/shoryuken/extensions/active_job_adapter_spec.rb +64 -0
- data/spec/shoryuken/fetcher_spec.rb +101 -18
- data/spec/shoryuken/manager_spec.rb +54 -26
- data/spec/shoryuken/middleware/chain_spec.rb +17 -5
- data/spec/shoryuken/middleware/server/auto_delete_spec.rb +9 -7
- data/spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb +4 -4
- data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +6 -4
- data/spec/shoryuken/middleware/server/timing_spec.rb +5 -3
- data/spec/shoryuken/options_spec.rb +180 -0
- data/spec/shoryuken/{polling_spec.rb → polling/strict_priority_spec.rb} +2 -101
- data/spec/shoryuken/polling/weighted_round_robin_spec.rb +99 -0
- data/spec/shoryuken/processor_spec.rb +26 -127
- data/spec/shoryuken/queue_spec.rb +115 -41
- data/spec/shoryuken/runner_spec.rb +3 -4
- data/spec/shoryuken/util_spec.rb +24 -0
- data/spec/shoryuken/worker/default_executor_spec.rb +105 -0
- data/spec/shoryuken/worker/inline_executor_spec.rb +49 -0
- data/spec/shoryuken/worker_spec.rb +35 -96
- data/spec/shoryuken_spec.rb +0 -59
- data/spec/spec_helper.rb +14 -3
- data/test_workers/endless_interruptive_worker.rb +2 -2
- data/test_workers/endless_uninterruptive_worker.rb +4 -4
- metadata +31 -12
- data/lib/shoryuken/polling.rb +0 -204
data/lib/shoryuken/version.rb
CHANGED
|
@@ -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
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Shoryuken
|
|
2
|
+
module Worker
|
|
3
|
+
class InlineExecutor
|
|
4
|
+
class << self
|
|
5
|
+
def perform_async(worker_class, body, _options = {})
|
|
6
|
+
body = JSON.dump(body) if body.is_a?(Hash)
|
|
7
|
+
|
|
8
|
+
sqs_msg = OpenStruct.new(
|
|
9
|
+
body: body,
|
|
10
|
+
attributes: nil,
|
|
11
|
+
md5_of_body: nil,
|
|
12
|
+
md5_of_message_attributes: nil,
|
|
13
|
+
message_attributes: nil,
|
|
14
|
+
message_id: nil,
|
|
15
|
+
receipt_handle: nil,
|
|
16
|
+
delete: nil
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
call(worker_class, sqs_msg)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def perform_in(worker_class, _interval, body, options = {})
|
|
23
|
+
worker_class.perform_async(body, options)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def call(worker_class, sqs_msg)
|
|
29
|
+
parsed_body = BodyParser.parse(worker_class, sqs_msg)
|
|
30
|
+
batch = worker_class.shoryuken_options_hash['batch']
|
|
31
|
+
args = batch ? [[sqs_msg], [parsed_body]] : [sqs_msg, parsed_body]
|
|
32
|
+
worker_class.new.perform(*args)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/shoryuken/worker.rb
CHANGED
|
@@ -2,33 +2,16 @@ module Shoryuken
|
|
|
2
2
|
module Worker
|
|
3
3
|
def self.included(base)
|
|
4
4
|
base.extend(ClassMethods)
|
|
5
|
+
base.shoryuken_class_attribute :shoryuken_options_hash
|
|
5
6
|
end
|
|
6
7
|
|
|
7
8
|
module ClassMethods
|
|
8
9
|
def perform_async(body, options = {})
|
|
9
|
-
|
|
10
|
-
options[:message_attributes]['shoryuken_class'] = {
|
|
11
|
-
string_value: self.to_s,
|
|
12
|
-
data_type: 'String'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
options[:message_body] = body
|
|
16
|
-
|
|
17
|
-
queue = options.delete(:queue) || get_shoryuken_options['queue']
|
|
18
|
-
|
|
19
|
-
Shoryuken::Client.queues(queue).send_message(options)
|
|
10
|
+
Shoryuken.worker_executor.perform_async(self, body, options)
|
|
20
11
|
end
|
|
21
12
|
|
|
22
13
|
def perform_in(interval, body, options = {})
|
|
23
|
-
interval
|
|
24
|
-
now = Time.now.to_f
|
|
25
|
-
ts = (interval < 1_000_000_000 ? (now + interval).to_f : interval)
|
|
26
|
-
|
|
27
|
-
delay = (ts - now).ceil
|
|
28
|
-
|
|
29
|
-
raise 'The maximum allowed delay is 15 minutes' if delay > 15 * 60
|
|
30
|
-
|
|
31
|
-
perform_async(body, options.merge(delay_seconds: delay))
|
|
14
|
+
Shoryuken.worker_executor.perform_in(self, interval, body, options)
|
|
32
15
|
end
|
|
33
16
|
|
|
34
17
|
alias_method :perform_at, :perform_in
|
|
@@ -40,7 +23,7 @@ module Shoryuken
|
|
|
40
23
|
end
|
|
41
24
|
|
|
42
25
|
def shoryuken_options(opts = {})
|
|
43
|
-
|
|
26
|
+
self.shoryuken_options_hash = get_shoryuken_options.merge(stringify_keys(opts || {}))
|
|
44
27
|
normalize_worker_queue!
|
|
45
28
|
end
|
|
46
29
|
|
|
@@ -48,34 +31,96 @@ module Shoryuken
|
|
|
48
31
|
!!get_shoryuken_options['auto_visibility_timeout']
|
|
49
32
|
end
|
|
50
33
|
|
|
34
|
+
def exponential_backoff?
|
|
35
|
+
!!get_shoryuken_options['retry_intervals']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def auto_delete?
|
|
39
|
+
!!(get_shoryuken_options['delete'] || get_shoryuken_options['auto_delete'])
|
|
40
|
+
end
|
|
41
|
+
|
|
51
42
|
def get_shoryuken_options # :nodoc:
|
|
52
|
-
|
|
43
|
+
shoryuken_options_hash || Shoryuken.default_worker_options
|
|
53
44
|
end
|
|
54
45
|
|
|
55
46
|
def stringify_keys(hash) # :nodoc:
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
new_hash = {}
|
|
48
|
+
hash.each { |key, value| new_hash[key.to_s] = value }
|
|
49
|
+
new_hash
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def shoryuken_class_attribute(*attrs) # :nodoc:
|
|
53
|
+
attrs.each do |name|
|
|
54
|
+
singleton_class.instance_eval do
|
|
55
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
|
56
|
+
end
|
|
57
|
+
define_singleton_method(name) { nil }
|
|
58
|
+
|
|
59
|
+
ivar = "@#{name}"
|
|
60
|
+
|
|
61
|
+
singleton_class.instance_eval do
|
|
62
|
+
m = "#{name}="
|
|
63
|
+
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
define_singleton_method("#{name}=") do |val|
|
|
67
|
+
singleton_class.class_eval do
|
|
68
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
|
69
|
+
define_method(name) { val }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# singleton? backwards compatibility for ruby < 2.1
|
|
73
|
+
singleton_klass = respond_to?(:singleton?) ? singleton? : self != ancestors.first
|
|
74
|
+
|
|
75
|
+
if singleton_klass
|
|
76
|
+
class_eval do
|
|
77
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
|
78
|
+
define_method(name) do
|
|
79
|
+
if instance_variable_defined? ivar
|
|
80
|
+
instance_variable_get ivar
|
|
81
|
+
else
|
|
82
|
+
singleton_class.send name
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
val
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# instance reader
|
|
91
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
|
92
|
+
define_method(name) do
|
|
93
|
+
if instance_variable_defined?(ivar)
|
|
94
|
+
instance_variable_get ivar
|
|
95
|
+
else
|
|
96
|
+
self.class.public_send name
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# instance writer
|
|
101
|
+
m = "#{name}="
|
|
102
|
+
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
|
103
|
+
attr_writer name
|
|
58
104
|
end
|
|
59
|
-
hash
|
|
60
105
|
end
|
|
61
106
|
|
|
62
107
|
private
|
|
63
108
|
|
|
64
109
|
def normalize_worker_queue!
|
|
65
|
-
queue =
|
|
110
|
+
queue = shoryuken_options_hash['queue']
|
|
66
111
|
if queue.respond_to?(:call)
|
|
67
112
|
queue = queue.call
|
|
68
|
-
|
|
113
|
+
shoryuken_options_hash['queue'] = queue
|
|
69
114
|
end
|
|
70
115
|
|
|
71
|
-
case
|
|
116
|
+
case shoryuken_options_hash['queue']
|
|
72
117
|
when Array
|
|
73
|
-
|
|
118
|
+
shoryuken_options_hash['queue'].map!(&:to_s)
|
|
74
119
|
when Symbol
|
|
75
|
-
|
|
120
|
+
shoryuken_options_hash['queue'] = shoryuken_options_hash['queue'].to_s
|
|
76
121
|
end
|
|
77
122
|
|
|
78
|
-
[
|
|
123
|
+
[shoryuken_options_hash['queue']].flatten.compact.each(&method(:register_worker))
|
|
79
124
|
end
|
|
80
125
|
|
|
81
126
|
def register_worker(queue)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Shoryuken
|
|
2
2
|
class WorkerRegistry
|
|
3
|
-
def batch_receive_messages?(
|
|
3
|
+
def batch_receive_messages?(_queue)
|
|
4
4
|
# true if the workers for queue support batch processing of messages
|
|
5
5
|
fail NotImplementedError
|
|
6
6
|
end
|
|
@@ -10,7 +10,7 @@ module Shoryuken
|
|
|
10
10
|
fail NotImplementedError
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def fetch_worker(
|
|
13
|
+
def fetch_worker(_queue, _message)
|
|
14
14
|
# must return an instance of the worker that handles
|
|
15
15
|
# message received on queue
|
|
16
16
|
fail NotImplementedError
|
|
@@ -21,12 +21,12 @@ module Shoryuken
|
|
|
21
21
|
fail NotImplementedError
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def register_worker(
|
|
24
|
+
def register_worker(_queue, _clazz)
|
|
25
25
|
# must register the worker as a consumer of messages from queue
|
|
26
26
|
fail NotImplementedError
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def workers(
|
|
29
|
+
def workers(_queue)
|
|
30
30
|
# must return the list of workers registered for queue, or []
|
|
31
31
|
fail NotImplementedError
|
|
32
32
|
end
|
data/lib/shoryuken.rb
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
require 'yaml'
|
|
2
2
|
require 'json'
|
|
3
3
|
require 'aws-sdk-core'
|
|
4
|
+
begin
|
|
5
|
+
require 'aws-sdk-sqs' unless defined?(Aws::SQS)
|
|
6
|
+
rescue LoadError
|
|
7
|
+
fail "AWS SDK 3 requires aws-sdk-sqs to be installed separately. Please add gem 'aws-sdk-sqs' to your Gemfile"
|
|
8
|
+
end
|
|
4
9
|
require 'time'
|
|
5
10
|
require 'concurrent'
|
|
11
|
+
require 'forwardable'
|
|
6
12
|
|
|
7
13
|
require 'shoryuken/version'
|
|
8
14
|
require 'shoryuken/core_ext'
|
|
@@ -13,6 +19,8 @@ require 'shoryuken/queue'
|
|
|
13
19
|
require 'shoryuken/message'
|
|
14
20
|
require 'shoryuken/client'
|
|
15
21
|
require 'shoryuken/worker'
|
|
22
|
+
require 'shoryuken/worker/default_executor'
|
|
23
|
+
require 'shoryuken/worker/inline_executor'
|
|
16
24
|
require 'shoryuken/worker_registry'
|
|
17
25
|
require 'shoryuken/default_worker_registry'
|
|
18
26
|
require 'shoryuken/middleware/chain'
|
|
@@ -20,184 +28,57 @@ require 'shoryuken/middleware/server/auto_delete'
|
|
|
20
28
|
Shoryuken::Middleware::Server.autoload :AutoExtendVisibility, 'shoryuken/middleware/server/auto_extend_visibility'
|
|
21
29
|
require 'shoryuken/middleware/server/exponential_backoff_retry'
|
|
22
30
|
require 'shoryuken/middleware/server/timing'
|
|
23
|
-
require 'shoryuken/polling'
|
|
31
|
+
require 'shoryuken/polling/base'
|
|
32
|
+
require 'shoryuken/polling/weighted_round_robin'
|
|
33
|
+
require 'shoryuken/polling/strict_priority'
|
|
24
34
|
require 'shoryuken/manager'
|
|
25
35
|
require 'shoryuken/launcher'
|
|
26
36
|
require 'shoryuken/processor'
|
|
37
|
+
require 'shoryuken/body_parser'
|
|
27
38
|
require 'shoryuken/fetcher'
|
|
39
|
+
require 'shoryuken/options'
|
|
28
40
|
|
|
29
41
|
module Shoryuken
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
@@start_callback
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def start_callback=(start_callback)
|
|
74
|
-
@@start_callback = start_callback
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def stop_callback
|
|
78
|
-
@@stop_callback
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def stop_callback=(stop_callback)
|
|
82
|
-
@@stop_callback = stop_callback
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def active_job_queue_name_prefixing
|
|
86
|
-
@@active_job_queue_name_prefixing
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def active_job_queue_name_prefixing=(active_job_queue_name_prefixing)
|
|
90
|
-
@@active_job_queue_name_prefixing = active_job_queue_name_prefixing
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def sqs_client
|
|
94
|
-
@@sqs_client ||= Aws::SQS::Client.new
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def sqs_client=(sqs_client)
|
|
98
|
-
@@sqs_client = sqs_client
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def sqs_client_receive_message_opts
|
|
102
|
-
@@sqs_client_receive_message_opts
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def sqs_client_receive_message_opts=(sqs_client_receive_message_opts)
|
|
106
|
-
@@sqs_client_receive_message_opts = sqs_client_receive_message_opts
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def options
|
|
110
|
-
@@options ||= DEFAULTS.dup
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def logger
|
|
114
|
-
Shoryuken::Logging.logger
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def register_worker(*args)
|
|
118
|
-
@@worker_registry.register_worker(*args)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def configure_server
|
|
122
|
-
yield self if server?
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def server_middleware
|
|
126
|
-
@@server_chain ||= default_server_middleware
|
|
127
|
-
yield @@server_chain if block_given?
|
|
128
|
-
@@server_chain
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def configure_client
|
|
132
|
-
yield self unless server?
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def client_middleware
|
|
136
|
-
@@client_chain ||= default_client_middleware
|
|
137
|
-
yield @@client_chain if block_given?
|
|
138
|
-
@@client_chain
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def default_worker_options
|
|
142
|
-
@@default_worker_options ||= {
|
|
143
|
-
'queue' => 'default',
|
|
144
|
-
'delete' => false,
|
|
145
|
-
'auto_delete' => false,
|
|
146
|
-
'auto_visibility_timeout' => false,
|
|
147
|
-
'retry_intervals' => nil,
|
|
148
|
-
'batch' => false
|
|
149
|
-
}
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def default_worker_options=(default_worker_options)
|
|
153
|
-
@@default_worker_options = default_worker_options
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def on_start(&block)
|
|
157
|
-
@@start_callback = block
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def on_stop(&block)
|
|
161
|
-
@@stop_callback = block
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
# Register a block to run at a point in the Shoryuken lifecycle.
|
|
165
|
-
# :startup, :quiet or :shutdown are valid events.
|
|
166
|
-
#
|
|
167
|
-
# Shoryuken.configure_server do |config|
|
|
168
|
-
# config.on(:shutdown) do
|
|
169
|
-
# puts "Goodbye cruel world!"
|
|
170
|
-
# end
|
|
171
|
-
# end
|
|
172
|
-
def on(event, &block)
|
|
173
|
-
fail ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
|
|
174
|
-
fail ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
|
|
175
|
-
options[:lifecycle_events][event] << block
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
private
|
|
179
|
-
|
|
180
|
-
def default_server_middleware
|
|
181
|
-
Middleware::Chain.new do |m|
|
|
182
|
-
m.add Middleware::Server::Timing
|
|
183
|
-
m.add Middleware::Server::ExponentialBackoffRetry
|
|
184
|
-
m.add Middleware::Server::AutoDelete
|
|
185
|
-
m.add Middleware::Server::AutoExtendVisibility
|
|
186
|
-
if defined?(::ActiveRecord::Base)
|
|
187
|
-
require 'shoryuken/middleware/server/active_record'
|
|
188
|
-
m.add Middleware::Server::ActiveRecord
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def default_client_middleware
|
|
194
|
-
Middleware::Chain.new
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
def server?
|
|
198
|
-
defined?(Shoryuken::CLI)
|
|
199
|
-
end
|
|
200
|
-
end
|
|
42
|
+
extend SingleForwardable
|
|
43
|
+
|
|
44
|
+
def_delegators(
|
|
45
|
+
:'Shoryuken::Options',
|
|
46
|
+
:active_job?,
|
|
47
|
+
:add_group,
|
|
48
|
+
:groups,
|
|
49
|
+
:add_queue,
|
|
50
|
+
:ungrouped_queues,
|
|
51
|
+
:worker_registry,
|
|
52
|
+
:worker_registry=,
|
|
53
|
+
:worker_executor,
|
|
54
|
+
:worker_executor=,
|
|
55
|
+
:launcher_executor,
|
|
56
|
+
:launcher_executor=,
|
|
57
|
+
:polling_strategy,
|
|
58
|
+
:start_callback,
|
|
59
|
+
:start_callback=,
|
|
60
|
+
:stop_callback,
|
|
61
|
+
:stop_callback=,
|
|
62
|
+
:active_job_queue_name_prefixing,
|
|
63
|
+
:active_job_queue_name_prefixing=,
|
|
64
|
+
:sqs_client,
|
|
65
|
+
:sqs_client=,
|
|
66
|
+
:sqs_client_receive_message_opts,
|
|
67
|
+
:sqs_client_receive_message_opts=,
|
|
68
|
+
:options,
|
|
69
|
+
:logger,
|
|
70
|
+
:register_worker,
|
|
71
|
+
:configure_server,
|
|
72
|
+
:server?,
|
|
73
|
+
:server_middleware,
|
|
74
|
+
:configure_client,
|
|
75
|
+
:client_middleware,
|
|
76
|
+
:default_worker_options,
|
|
77
|
+
:default_worker_options=,
|
|
78
|
+
:on_start,
|
|
79
|
+
:on_stop,
|
|
80
|
+
:on
|
|
81
|
+
)
|
|
201
82
|
end
|
|
202
83
|
|
|
203
|
-
require 'shoryuken/extensions/active_job_adapter' if
|
|
84
|
+
require 'shoryuken/extensions/active_job_adapter' if Shoryuken.active_job?
|
data/shoryuken.gemspec
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
lib = File.expand_path('
|
|
1
|
+
|
|
2
|
+
lib = File.expand_path('lib', __dir__)
|
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'shoryuken/version'
|
|
5
5
|
|
|
@@ -13,17 +13,17 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.license = 'LGPL-3.0'
|
|
14
14
|
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
|
16
|
-
spec.executables = %w
|
|
16
|
+
spec.executables = %w[shoryuken]
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
18
18
|
spec.require_paths = ['lib']
|
|
19
19
|
|
|
20
20
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
|
21
|
+
spec.add_development_dependency 'dotenv'
|
|
22
|
+
spec.add_development_dependency 'pry-byebug'
|
|
21
23
|
spec.add_development_dependency 'rake'
|
|
22
24
|
spec.add_development_dependency 'rspec'
|
|
23
|
-
spec.add_development_dependency 'pry-byebug'
|
|
24
|
-
spec.add_development_dependency 'dotenv'
|
|
25
25
|
|
|
26
|
-
spec.add_dependency 'aws-sdk-core', '
|
|
26
|
+
spec.add_dependency 'aws-sdk-core', '>= 2'
|
|
27
27
|
spec.add_dependency 'concurrent-ruby'
|
|
28
28
|
spec.add_dependency 'thor'
|
|
29
29
|
end
|
|
@@ -4,27 +4,33 @@ require 'shoryuken/launcher'
|
|
|
4
4
|
require 'securerandom'
|
|
5
5
|
|
|
6
6
|
RSpec.describe Shoryuken::Launcher do
|
|
7
|
-
describe 'Consuming messages', slow:
|
|
7
|
+
describe 'Consuming messages', slow: true do
|
|
8
8
|
before do
|
|
9
|
+
Aws.config[:stub_responses] = false
|
|
10
|
+
Aws.config[:region] = 'us-east-1'
|
|
11
|
+
|
|
9
12
|
StandardWorker.received_messages = 0
|
|
10
13
|
|
|
11
|
-
queue = "
|
|
14
|
+
queue = "shoryuken-travis-#{StandardWorker}-#{SecureRandom.uuid}"
|
|
12
15
|
|
|
13
|
-
Shoryuken::Client.sqs.create_queue
|
|
16
|
+
Shoryuken::Client.sqs.create_queue(queue_name: queue)
|
|
14
17
|
|
|
15
|
-
Shoryuken.
|
|
18
|
+
Shoryuken.add_group('default', 1)
|
|
19
|
+
Shoryuken.add_queue(queue, 1, 'default')
|
|
16
20
|
|
|
17
21
|
StandardWorker.get_shoryuken_options['queue'] = queue
|
|
18
22
|
|
|
19
|
-
Shoryuken.register_worker
|
|
23
|
+
Shoryuken.register_worker(queue, StandardWorker)
|
|
20
24
|
end
|
|
21
25
|
|
|
22
26
|
after do
|
|
27
|
+
Aws.config[:stub_responses] = true
|
|
28
|
+
|
|
23
29
|
queue_url = Shoryuken::Client.sqs.get_queue_url(
|
|
24
30
|
queue_name: StandardWorker.get_shoryuken_options['queue']
|
|
25
31
|
).queue_url
|
|
26
32
|
|
|
27
|
-
Shoryuken::Client.sqs.delete_queue
|
|
33
|
+
Shoryuken::Client.sqs.delete_queue(queue_url: queue_url)
|
|
28
34
|
end
|
|
29
35
|
|
|
30
36
|
it 'consumes as a command worker' do
|
|
@@ -61,7 +67,7 @@ RSpec.describe Shoryuken::Launcher do
|
|
|
61
67
|
end
|
|
62
68
|
|
|
63
69
|
def poll_queues_until
|
|
64
|
-
subject.
|
|
70
|
+
subject.start
|
|
65
71
|
|
|
66
72
|
Timeout::timeout(10) do
|
|
67
73
|
begin
|
|
@@ -79,7 +85,7 @@ RSpec.describe Shoryuken::Launcher do
|
|
|
79
85
|
|
|
80
86
|
shoryuken_options auto_delete: true
|
|
81
87
|
|
|
82
|
-
def perform(sqs_msg,
|
|
88
|
+
def perform(sqs_msg, _body)
|
|
83
89
|
@@received_messages += Array(sqs_msg).size
|
|
84
90
|
end
|
|
85
91
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'shoryuken/body_parser'
|
|
3
|
+
|
|
4
|
+
RSpec.describe Shoryuken::BodyParser do
|
|
5
|
+
let(:sqs_msg) { double }
|
|
6
|
+
|
|
7
|
+
describe '#parser' do
|
|
8
|
+
it 'parses the body into JSON' do
|
|
9
|
+
TestWorker.get_shoryuken_options['body_parser'] = :json
|
|
10
|
+
|
|
11
|
+
body = { 'test' => 'hi' }
|
|
12
|
+
|
|
13
|
+
allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
|
|
14
|
+
|
|
15
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq(body)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'parses the body calling the proc' do
|
|
19
|
+
TestWorker.get_shoryuken_options['body_parser'] = proc { |sqs_msg| "*#{sqs_msg.body}*" }
|
|
20
|
+
|
|
21
|
+
allow(sqs_msg).to receive(:body).and_return('test')
|
|
22
|
+
|
|
23
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq('*test*')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'parses the body as text' do
|
|
27
|
+
TestWorker.get_shoryuken_options['body_parser'] = :text
|
|
28
|
+
|
|
29
|
+
body = 'test'
|
|
30
|
+
|
|
31
|
+
allow(sqs_msg).to receive(:body).and_return(body)
|
|
32
|
+
|
|
33
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq('test')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'parses calling `.load`' do
|
|
37
|
+
TestWorker.get_shoryuken_options['body_parser'] = Class.new do
|
|
38
|
+
def self.load(*args)
|
|
39
|
+
JSON.load(*args)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
body = { 'test' => 'hi' }
|
|
44
|
+
|
|
45
|
+
allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
|
|
46
|
+
|
|
47
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq(body)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'parses calling `.parse`' do
|
|
51
|
+
TestWorker.get_shoryuken_options['body_parser'] = Class.new do
|
|
52
|
+
def self.parse(*args)
|
|
53
|
+
JSON.parse(*args)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
body = { 'test' => 'hi' }
|
|
58
|
+
|
|
59
|
+
allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
|
|
60
|
+
|
|
61
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq(body)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'when parse errors' do
|
|
65
|
+
before do
|
|
66
|
+
TestWorker.get_shoryuken_options['body_parser'] = :json
|
|
67
|
+
|
|
68
|
+
allow(sqs_msg).to receive(:body).and_return('invalid JSON')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
specify do
|
|
72
|
+
expect { described_class.parse(TestWorker, sqs_msg) }
|
|
73
|
+
.to raise_error(JSON::ParserError, /unexpected token at 'invalid JSON'/)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context 'when `object_type: nil`' do
|
|
78
|
+
it 'parses the body as text' do
|
|
79
|
+
TestWorker.get_shoryuken_options['body_parser'] = nil
|
|
80
|
+
|
|
81
|
+
body = 'test'
|
|
82
|
+
|
|
83
|
+
allow(sqs_msg).to receive(:body).and_return(body)
|
|
84
|
+
|
|
85
|
+
expect(described_class.parse(TestWorker, sqs_msg)).to eq(body)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|