shoryuken 3.1.8 → 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.
@@ -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
@@ -38,6 +38,22 @@ RSpec.describe Shoryuken::Fetcher do
38
38
  subject.fetch(queue_config, limit)
39
39
  end
40
40
 
41
+ it 'logs debug only' do
42
+ # See https://github.com/phstc/shoryuken/issues/435
43
+ logger = double 'logger'
44
+
45
+ allow(subject).to receive(:logger).and_return(logger)
46
+
47
+ expect(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
48
+
49
+ expect(queue).to receive(:receive_messages).and_return([double('SQS Msg')])
50
+
51
+ expect(logger).to receive(:debug).exactly(3).times
52
+ expect(logger).to_not receive(:info)
53
+
54
+ subject.fetch(queue_config, limit)
55
+ end
56
+
41
57
  context 'when receive options per queue' do
42
58
  let(:limit) { 5 }
43
59
 
@@ -70,7 +70,7 @@ RSpec.describe Shoryuken::Manager do
70
70
  q = Shoryuken::Polling::QueueConfiguration.new(queue, {})
71
71
 
72
72
  expect(fetcher).to receive(:fetch).with(q, concurrency).and_return(messages)
73
- expect(subject).to receive(:fire_event).with(:dispatch)
73
+ expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
74
74
  expect(Shoryuken::Processor).to receive(:process).with(q, message)
75
75
  expect(Shoryuken.logger).to_not receive(:info)
76
76
 
@@ -83,7 +83,7 @@ RSpec.describe Shoryuken::Manager do
83
83
  q = Shoryuken::Polling::QueueConfiguration.new(queue, {})
84
84
 
85
85
  expect(fetcher).to receive(:fetch).with(q, described_class::BATCH_LIMIT).and_return(messages)
86
- expect(subject).to receive(:fire_event).with(:dispatch)
86
+ expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
87
87
  allow(subject).to receive(:batched_queue?).with(q).and_return(true)
88
88
  expect(Shoryuken::Processor).to receive(:process).with(q, messages)
89
89
  expect(Shoryuken.logger).to_not receive(:info)
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Shoryuken::Middleware::Chain do
3
+ RSpec.describe Shoryuken::Middleware::Chain do
4
4
  class CustomMiddleware
5
5
  def initialize(name, recorder)
6
6
  @name = name
@@ -14,20 +14,32 @@ describe Shoryuken::Middleware::Chain do
14
14
  end
15
15
  end
16
16
 
17
+ class CustomMiddlewareB < CustomMiddleware; end
18
+
17
19
  it 'supports custom middleware' do
18
20
  subject.add CustomMiddleware, 1, []
19
21
 
20
22
  expect(CustomMiddleware).to eq subject.entries.last.klass
21
23
  end
22
24
 
25
+ it 'can add middleware to the front of chain' do
26
+ subject.prepend CustomMiddleware, 1, []
27
+
28
+ expect([CustomMiddleware]).to eq subject.entries.map(&:klass)
29
+
30
+ subject.prepend CustomMiddlewareB, 1, []
31
+
32
+ expect([CustomMiddlewareB, CustomMiddleware]).to eq subject.entries.map(&:klass)
33
+ end
34
+
23
35
  it 'invokes a middleware' do
24
36
  recorder = []
25
- subject.add CustomMiddleware, 'Pablo', recorder
37
+ subject.add CustomMiddleware, 'custom', recorder
26
38
 
27
39
  final_action = nil
28
40
  subject.invoke { final_action = true }
29
41
  expect(final_action).to eq true
30
- expect(recorder).to eq [%w[Pablo before], %w[Pablo after]]
42
+ expect(recorder).to eq [%w(custom before), %w(custom after)]
31
43
  end
32
44
 
33
45
  class NonYieldingMiddleware
@@ -37,7 +49,7 @@ describe Shoryuken::Middleware::Chain do
37
49
  it 'allows middleware to abruptly stop processing rest of chain' do
38
50
  recorder = []
39
51
  subject.add NonYieldingMiddleware
40
- subject.add CustomMiddleware, 'Pablo', recorder
52
+ subject.add CustomMiddleware, 'custom', recorder
41
53
 
42
54
  final_action = nil
43
55
  subject.invoke { final_action = true }
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'shoryuken/processor'
3
- require 'shoryuken/manager'
4
2
 
5
3
  RSpec.describe Shoryuken::Processor do
6
4
  let(:manager) { double Shoryuken::Manager }
@@ -8,12 +6,14 @@ RSpec.describe Shoryuken::Processor do
8
6
  let(:queue) { 'default' }
9
7
 
10
8
  let(:sqs_msg) do
11
- double Shoryuken::Message,
9
+ double(
10
+ Shoryuken::Message,
12
11
  queue_url: queue,
13
12
  body: 'test',
14
13
  message_attributes: {},
15
14
  message_id: SecureRandom.uuid,
16
15
  receipt_handle: SecureRandom.uuid
16
+ )
17
17
  end
18
18
 
19
19
  before do
@@ -25,101 +25,15 @@ RSpec.describe Shoryuken::Processor do
25
25
  subject { described_class.new(queue, sqs_msg) }
26
26
 
27
27
  describe '#process' do
28
- it 'parses the body into JSON' do
29
- TestWorker.get_shoryuken_options['body_parser'] = :json
28
+ it 'sets log context' do
29
+ expect(Shoryuken::Logging).to receive(:with_context).with("TestWorker/#{queue}/#{sqs_msg.message_id}")
30
30
 
31
- body = { 'test' => 'hi' }
32
-
33
- expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, body)
34
-
35
- allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
31
+ allow_any_instance_of(TestWorker).to receive(:perform)
32
+ allow(sqs_msg).to receive(:body)
36
33
 
37
34
  subject.process
38
35
  end
39
36
 
40
- it 'parses the body calling the proc' do
41
- TestWorker.get_shoryuken_options['body_parser'] = proc { |sqs_msg| "*#{sqs_msg.body}*" }
42
-
43
- expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, '*test*')
44
-
45
- allow(sqs_msg).to receive(:body).and_return('test')
46
-
47
- subject.process
48
- end
49
-
50
- it 'parses the body as text' do
51
- TestWorker.get_shoryuken_options['body_parser'] = :text
52
-
53
- body = 'test'
54
-
55
- expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, body)
56
-
57
- allow(sqs_msg).to receive(:body).and_return(body)
58
-
59
- subject.process
60
- end
61
-
62
- it 'parses calling `.load`' do
63
- TestWorker.get_shoryuken_options['body_parser'] = Class.new do
64
- def self.load(*args)
65
- JSON.load(*args)
66
- end
67
- end
68
-
69
- body = { 'test' => 'hi' }
70
-
71
- expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, body)
72
-
73
- allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
74
-
75
- subject.process
76
- end
77
-
78
- it 'parses calling `.parse`' do
79
- TestWorker.get_shoryuken_options['body_parser'] = Class.new do
80
- def self.parse(*args)
81
- JSON.parse(*args)
82
- end
83
- end
84
-
85
- body = { 'test' => 'hi' }
86
-
87
- expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, body)
88
-
89
- allow(sqs_msg).to receive(:body).and_return(JSON.dump(body))
90
-
91
- subject.process
92
- end
93
-
94
- context 'when parse errors' do
95
- before do
96
- TestWorker.get_shoryuken_options['body_parser'] = :json
97
-
98
- allow(sqs_msg).to receive(:body).and_return('invalid JSON')
99
- end
100
-
101
- specify do
102
- expect(subject.logger).to receive(:error).twice
103
-
104
- expect { subject.process }.
105
- to raise_error(JSON::ParserError, /unexpected token at 'invalid JSON'/)
106
- end
107
- end
108
-
109
- context 'when `object_type: nil`' do
110
- it 'parses the body as text' do
111
- TestWorker.get_shoryuken_options['body_parser'] = nil
112
-
113
- body = 'test'
114
-
115
- expect_any_instance_of(TestWorker).to receive(:perform).with(sqs_msg, body)
116
-
117
- allow(sqs_msg).to receive(:body).and_return(body)
118
-
119
- subject.process
120
- end
121
- end
122
-
123
37
  context 'when custom middleware' do
124
38
  let(:queue) { 'worker_called_middleware' }
125
39
 
@@ -220,15 +134,19 @@ RSpec.describe Shoryuken::Processor do
220
134
 
221
135
  context 'when shoryuken_class header' do
222
136
  let(:sqs_msg) do
223
- double Shoryuken::Message,
137
+ double(
138
+ Shoryuken::Message,
224
139
  queue_url: queue,
225
140
  body: 'test',
226
141
  message_attributes: {
227
142
  'shoryuken_class' => {
228
143
  string_value: TestWorker.to_s,
229
- data_type: 'String' }},
230
- message_id: SecureRandom.uuid,
231
- receipt_handle: SecureRandom.uuid
144
+ data_type: 'String'
145
+ }
146
+ },
147
+ message_id: SecureRandom.uuid,
148
+ receipt_handle: SecureRandom.uuid
149
+ )
232
150
  end
233
151
 
234
152
  it 'performs without delete' do
@@ -9,7 +9,7 @@ describe 'Shoryuken::Util' do
9
9
 
10
10
  describe '#unparse_queues' do
11
11
  it 'returns queues and weights' do
12
- queues = %w[queue1 queue1 queue2 queue3 queue4 queue4 queue4]
12
+ queues = %w(queue1 queue1 queue2 queue3 queue4 queue4 queue4)
13
13
 
14
14
  expect(subject.unparse_queues(queues)).to eq([['queue1', 2], ['queue2', 1], ['queue3', 1], ['queue4', 3]])
15
15
  end
@@ -26,4 +26,28 @@ describe 'Shoryuken::Util' do
26
26
 
27
27
  it 'returns ActiveJob worker name'
28
28
  end
29
+
30
+ describe '#fire_event' do
31
+ let(:value_holder) { Object.new }
32
+ let(:callback_without_options) { proc { value_holder.value = :without_options } }
33
+ let(:callback_with_options) { proc { |options| value_holder.value = [:with_options, options] } }
34
+
35
+ after :all do
36
+ Shoryuken.options[:lifecycle_events].delete(:some_event)
37
+ end
38
+
39
+ it 'triggers callbacks that do not accept arguments' do
40
+ Shoryuken.options[:lifecycle_events][:some_event] = [callback_without_options]
41
+
42
+ expect(value_holder).to receive(:value=).with(:without_options)
43
+ subject.fire_event(:some_event)
44
+ end
45
+
46
+ it 'triggers callbacks that accept an argument' do
47
+ Shoryuken.options[:lifecycle_events][:some_event] = [callback_with_options]
48
+
49
+ expect(value_holder).to receive(:value=).with([:with_options, { my_option: :some_option }])
50
+ subject.fire_event(:some_event, false, my_option: :some_option)
51
+ end
52
+ end
29
53
  end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Shoryuken::Worker::DefaultExecutor do
4
+ let(:sqs_queue) { double 'SQS Queue' }
5
+ let(:queue) { 'default' }
6
+
7
+ before do
8
+ allow(Shoryuken::Client).to receive(:queues).with(queue).and_return(sqs_queue)
9
+ end
10
+
11
+ describe '.perform_in' do
12
+ it 'delays a message' do
13
+ expect(sqs_queue).to receive(:send_message).with(
14
+ message_attributes: {
15
+ 'shoryuken_class' => {
16
+ string_value: TestWorker.to_s,
17
+ data_type: 'String'
18
+ }
19
+ },
20
+ message_body: 'message',
21
+ delay_seconds: 60)
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(
36
+ message_attributes: {
37
+ 'shoryuken_class' => {
38
+ string_value: TestWorker.to_s,
39
+ data_type: 'String'
40
+ }
41
+ },
42
+ message_body: 'message',
43
+ delay_seconds: 60)
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
+
55
+ describe '.perform_async' do
56
+ it 'enqueues a message' do
57
+ expect(sqs_queue).to receive(:send_message).with(
58
+ message_attributes: {
59
+ 'shoryuken_class' => {
60
+ string_value: TestWorker.to_s,
61
+ data_type: 'String'
62
+ }
63
+ },
64
+ message_body: 'message')
65
+
66
+ TestWorker.perform_async('message')
67
+ end
68
+
69
+ it 'enqueues a message with options' do
70
+ expect(sqs_queue).to receive(:send_message).with(
71
+ delay_seconds: 60,
72
+ message_attributes: {
73
+ 'shoryuken_class' => {
74
+ string_value: TestWorker.to_s,
75
+ data_type: 'String'
76
+ }
77
+ },
78
+ message_body: 'delayed message')
79
+
80
+ TestWorker.perform_async('delayed message', delay_seconds: 60)
81
+ end
82
+
83
+ it 'accepts an `queue` option' do
84
+ new_queue = 'some_different_queue'
85
+
86
+ expect(Shoryuken::Client).to receive(:queues).with(new_queue).and_return(sqs_queue)
87
+
88
+ expect(sqs_queue).to receive(:send_message).with(
89
+ message_attributes: {
90
+ 'shoryuken_class' => {
91
+ string_value: TestWorker.to_s,
92
+ data_type: 'String'
93
+ }
94
+ },
95
+ message_body: 'delayed message')
96
+
97
+ TestWorker.perform_async('delayed message', queue: new_queue)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Shoryuken::Worker::InlineExecutor do
4
+ before do
5
+ Shoryuken.worker_executor = described_class
6
+ end
7
+
8
+ describe '.perform_async' do
9
+ specify do
10
+ expect_any_instance_of(TestWorker).to receive(:perform)
11
+
12
+ TestWorker.perform_async('test')
13
+ end
14
+ end
15
+
16
+ describe '.perform_in' do
17
+ specify do
18
+ expect_any_instance_of(TestWorker).to receive(:perform)
19
+
20
+ TestWorker.perform_in(60, 'test')
21
+ end
22
+ end
23
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe 'Shoryuken::Worker' do
3
+ RSpec.describe Shoryuken::Worker do
4
4
  let(:sqs_queue) { double 'SQS Queue' }
5
5
  let(:queue) { 'default' }
6
6
 
@@ -8,96 +8,6 @@ RSpec.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(
14
- message_attributes: {
15
- 'shoryuken_class' => {
16
- string_value: TestWorker.to_s,
17
- data_type: 'String'
18
- }
19
- },
20
- message_body: 'message',
21
- delay_seconds: 60)
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(
36
- message_attributes: {
37
- 'shoryuken_class' => {
38
- string_value: TestWorker.to_s,
39
- data_type: 'String'
40
- }
41
- },
42
- message_body: 'message',
43
- delay_seconds: 60)
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
-
55
- describe '.perform_async' do
56
- it 'enqueues a message' do
57
- expect(sqs_queue).to receive(:send_message).with(
58
- message_attributes: {
59
- 'shoryuken_class' => {
60
- string_value: TestWorker.to_s,
61
- data_type: 'String'
62
- }
63
- },
64
- message_body: 'message')
65
-
66
- TestWorker.perform_async('message')
67
- end
68
-
69
- it 'enqueues a message with options' do
70
- expect(sqs_queue).to receive(:send_message).with(
71
- delay_seconds: 60,
72
- message_attributes: {
73
- 'shoryuken_class' => {
74
- string_value: TestWorker.to_s,
75
- data_type: 'String'
76
- }
77
- },
78
- message_body: 'delayed message')
79
-
80
- TestWorker.perform_async('delayed message', delay_seconds: 60)
81
- end
82
-
83
- it 'accepts an `queue` option' do
84
- new_queue = 'some_different_queue'
85
-
86
- expect(Shoryuken::Client).to receive(:queues).with(new_queue).and_return(sqs_queue)
87
-
88
- expect(sqs_queue).to receive(:send_message).with(
89
- message_attributes: {
90
- 'shoryuken_class' => {
91
- string_value: TestWorker.to_s,
92
- data_type: 'String'
93
- }
94
- },
95
- message_body: 'delayed message')
96
-
97
- TestWorker.perform_async('delayed message', queue: new_queue)
98
- end
99
- end
100
-
101
11
  describe '.shoryuken_options' do
102
12
  it 'registers a worker' do
103
13
  expect(Shoryuken.worker_registry.workers('default')).to eq([TestWorker])
@@ -116,6 +26,20 @@ RSpec.describe 'Shoryuken::Worker' do
116
26
  expect(NewTestWorker.get_shoryuken_options['queue']).to eq 'production_default'
117
27
  end
118
28
 
29
+ it 'does not change the original hash' do
30
+ class TestWorker
31
+ include Shoryuken::Worker
32
+
33
+ OPT = { queue: :default }
34
+
35
+ shoryuken_options OPT
36
+ end
37
+
38
+ expect(TestWorker::OPT['queue']).to eq(nil)
39
+ expect(TestWorker.get_shoryuken_options['queue']).to eq('default')
40
+ expect(TestWorker::OPT[:queue]).to eq(:default)
41
+ end
42
+
119
43
  it 'accepts an array as a queue' do
120
44
  class WorkerMultipleQueues
121
45
  include Shoryuken::Worker
@@ -164,6 +88,23 @@ RSpec.describe 'Shoryuken::Worker' do
164
88
  expect(Shoryuken.worker_registry.workers('symbol_queue2')).to eq([WorkerMultipleSymbolQueues])
165
89
  expect(Shoryuken.worker_registry.workers('symbol_queue3')).to eq([WorkerMultipleSymbolQueues])
166
90
  end
91
+
92
+ it 'preserves parent class options' do
93
+ class ParentWorker
94
+ include Shoryuken::Worker
95
+
96
+ shoryuken_options queue: "myqueue", auto_delete: false
97
+ end
98
+
99
+ class ChildWorker < ParentWorker
100
+ shoryuken_options auto_delete: true
101
+ end
102
+
103
+ expect(ParentWorker.get_shoryuken_options['queue']).to eq("myqueue")
104
+ expect(ChildWorker.get_shoryuken_options['queue']).to eq("myqueue")
105
+ expect(ParentWorker.get_shoryuken_options['auto_delete']).to eq(false)
106
+ expect(ChildWorker.get_shoryuken_options['auto_delete']).to eq(true)
107
+ end
167
108
  end
168
109
 
169
110
  describe '.server_middleware' do