shoryuken 7.0.0.alpha2 → 7.0.0.rc1
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/.github/workflows/specs.yml +22 -9
- data/Appraisals +6 -12
- data/CHANGELOG.md +14 -0
- data/bin/cli/sqs.rb +1 -1
- data/bin/shoryuken +1 -1
- data/gemfiles/rails_7_2.gemfile +10 -10
- data/gemfiles/rails_8_0.gemfile +10 -10
- data/gemfiles/rails_8_1.gemfile +19 -0
- data/lib/shoryuken/extensions/active_job_adapter.rb +13 -0
- data/lib/shoryuken/helpers/timer_task.rb +66 -0
- data/lib/shoryuken/launcher.rb +14 -0
- data/lib/shoryuken/logging/base.rb +26 -0
- data/lib/shoryuken/logging/pretty.rb +25 -0
- data/lib/shoryuken/logging/without_timestamp.rb +25 -0
- data/lib/shoryuken/logging.rb +3 -23
- data/lib/shoryuken/message.rb +114 -1
- data/lib/shoryuken/middleware/chain.rb +138 -43
- data/lib/shoryuken/middleware/entry.rb +30 -0
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +1 -1
- data/lib/shoryuken/runner.rb +3 -0
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken/worker.rb +171 -0
- data/spec/integration/active_job_continuation_spec.rb +145 -0
- data/spec/shoryuken/extensions/active_job_continuation_spec.rb +110 -0
- data/spec/shoryuken/helpers/timer_task_spec.rb +298 -0
- data/spec/shoryuken/launcher_spec.rb +22 -0
- metadata +13 -3
- data/gemfiles/rails_7_0.gemfile +0 -19
- data/gemfiles/rails_7_1.gemfile +0 -19
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_job'
|
|
4
|
+
require 'shared_examples_for_active_job'
|
|
5
|
+
require 'shoryuken/extensions/active_job_adapter'
|
|
6
|
+
require 'shoryuken/extensions/active_job_extensions'
|
|
7
|
+
|
|
8
|
+
RSpec.describe 'ActiveJob Continuation support' do
|
|
9
|
+
let(:adapter) { ActiveJob::QueueAdapters::ShoryukenAdapter.new }
|
|
10
|
+
let(:job) do
|
|
11
|
+
job = TestJob.new
|
|
12
|
+
job.sqs_send_message_parameters = {}
|
|
13
|
+
job
|
|
14
|
+
end
|
|
15
|
+
let(:queue) { double('Queue', fifo?: false) }
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
allow(Shoryuken::Client).to receive(:queues).with(job.queue_name).and_return(queue)
|
|
19
|
+
allow(Shoryuken).to receive(:register_worker)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '#stopping?' do
|
|
23
|
+
context 'when Launcher is not initialized' do
|
|
24
|
+
it 'returns false' do
|
|
25
|
+
runner = instance_double(Shoryuken::Runner, launcher: nil)
|
|
26
|
+
allow(Shoryuken::Runner).to receive(:instance).and_return(runner)
|
|
27
|
+
|
|
28
|
+
expect(adapter.stopping?).to be false
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context 'when Launcher is initialized' do
|
|
33
|
+
let(:runner) { instance_double(Shoryuken::Runner) }
|
|
34
|
+
let(:launcher) { instance_double(Shoryuken::Launcher) }
|
|
35
|
+
|
|
36
|
+
before do
|
|
37
|
+
allow(Shoryuken::Runner).to receive(:instance).and_return(runner)
|
|
38
|
+
allow(runner).to receive(:launcher).and_return(launcher)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'returns false when not stopping' do
|
|
42
|
+
allow(launcher).to receive(:stopping?).and_return(false)
|
|
43
|
+
expect(adapter.stopping?).to be false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'returns true when stopping' do
|
|
47
|
+
allow(launcher).to receive(:stopping?).and_return(true)
|
|
48
|
+
expect(adapter.stopping?).to be true
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe '#enqueue_at with past timestamps' do
|
|
54
|
+
let(:past_timestamp) { Time.current.to_f - 60 } # 60 seconds ago
|
|
55
|
+
|
|
56
|
+
it 'enqueues with negative delay_seconds when timestamp is in the past' do
|
|
57
|
+
expect(queue).to receive(:send_message) do |hash|
|
|
58
|
+
expect(hash[:delay_seconds]).to be <= 0
|
|
59
|
+
expect(hash[:delay_seconds]).to be >= -61 # Allow for rounding and timing
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
adapter.enqueue_at(job, past_timestamp)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'does not raise an error for past timestamps' do
|
|
66
|
+
allow(queue).to receive(:send_message)
|
|
67
|
+
|
|
68
|
+
expect { adapter.enqueue_at(job, past_timestamp) }.not_to raise_error
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe '#enqueue_at with future timestamps' do
|
|
73
|
+
let(:future_timestamp) { Time.current.to_f + 60 } # 60 seconds from now
|
|
74
|
+
|
|
75
|
+
it 'enqueues with delay_seconds when timestamp is in the future' do
|
|
76
|
+
expect(queue).to receive(:send_message) do |hash|
|
|
77
|
+
expect(hash[:delay_seconds]).to be > 0
|
|
78
|
+
expect(hash[:delay_seconds]).to be <= 60
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
adapter.enqueue_at(job, future_timestamp)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe '#enqueue_at with current timestamp' do
|
|
86
|
+
let(:current_timestamp) { Time.current.to_f }
|
|
87
|
+
|
|
88
|
+
it 'enqueues with delay_seconds close to 0' do
|
|
89
|
+
expect(queue).to receive(:send_message) do |hash|
|
|
90
|
+
expect(hash[:delay_seconds]).to be_between(-1, 1) # Allow for timing/rounding
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
adapter.enqueue_at(job, current_timestamp)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe 'retry_on with zero wait' do
|
|
98
|
+
it 'allows immediate retries through continuation mechanism' do
|
|
99
|
+
# Simulate a job with retry_on configuration that uses zero wait
|
|
100
|
+
past_timestamp = Time.current.to_f - 1
|
|
101
|
+
|
|
102
|
+
expect(queue).to receive(:send_message) do |hash|
|
|
103
|
+
# Negative delay for past timestamp - SQS will handle immediate delivery
|
|
104
|
+
expect(hash[:delay_seconds]).to be <= 0
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
adapter.enqueue_at(job, past_timestamp)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Shoryuken::Helpers::TimerTask do
|
|
6
|
+
let(:execution_interval) { 0.1 }
|
|
7
|
+
let!(:timer_task) do
|
|
8
|
+
described_class.new(execution_interval: execution_interval) do
|
|
9
|
+
@execution_count = (@execution_count || 0) + 1
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#initialize' do
|
|
14
|
+
it 'creates a timer task with the specified interval' do
|
|
15
|
+
timer = described_class.new(execution_interval: 5) {}
|
|
16
|
+
expect(timer).to be_a(described_class)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'requires a block' do
|
|
20
|
+
expect { described_class.new(execution_interval: 5) }.to raise_error(ArgumentError, 'A block must be provided')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'requires a positive execution_interval' do
|
|
24
|
+
expect { described_class.new(execution_interval: 0) {} }.to raise_error(ArgumentError, 'execution_interval must be positive')
|
|
25
|
+
expect { described_class.new(execution_interval: -1) {} }.to raise_error(ArgumentError, 'execution_interval must be positive')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'accepts string numbers as execution_interval' do
|
|
29
|
+
timer = described_class.new(execution_interval: '5.5') {}
|
|
30
|
+
expect(timer.instance_variable_get(:@execution_interval)).to eq(5.5)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'raises ArgumentError for non-numeric execution_interval' do
|
|
34
|
+
expect { described_class.new(execution_interval: 'invalid') {} }.to raise_error(ArgumentError)
|
|
35
|
+
expect { described_class.new(execution_interval: nil) {} }.to raise_error(TypeError)
|
|
36
|
+
expect { described_class.new(execution_interval: {}) {} }.to raise_error(TypeError)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'stores the task block in @task instance variable' do
|
|
40
|
+
task_proc = proc { puts 'test' }
|
|
41
|
+
timer = described_class.new(execution_interval: 1, &task_proc)
|
|
42
|
+
expect(timer.instance_variable_get(:@task)).to eq(task_proc)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'stores the execution interval' do
|
|
46
|
+
timer = described_class.new(execution_interval: 5) {}
|
|
47
|
+
expect(timer.instance_variable_get(:@execution_interval)).to eq(5)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'initializes state variables correctly' do
|
|
51
|
+
timer = described_class.new(execution_interval: 1) {}
|
|
52
|
+
expect(timer.instance_variable_get(:@running)).to be false
|
|
53
|
+
expect(timer.instance_variable_get(:@killed)).to be false
|
|
54
|
+
expect(timer.instance_variable_get(:@thread)).to be_nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe '#execute' do
|
|
59
|
+
it 'returns self for method chaining' do
|
|
60
|
+
result = timer_task.execute
|
|
61
|
+
expect(result).to eq(timer_task)
|
|
62
|
+
timer_task.kill
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'sets @running to true when executed' do
|
|
66
|
+
timer_task.execute
|
|
67
|
+
expect(timer_task.instance_variable_get(:@running)).to be true
|
|
68
|
+
timer_task.kill
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'creates a new thread' do
|
|
72
|
+
timer_task.execute
|
|
73
|
+
thread = timer_task.instance_variable_get(:@thread)
|
|
74
|
+
expect(thread).to be_a(Thread)
|
|
75
|
+
timer_task.kill
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'does not start multiple times' do
|
|
79
|
+
timer_task.execute
|
|
80
|
+
first_thread = timer_task.instance_variable_get(:@thread)
|
|
81
|
+
timer_task.execute
|
|
82
|
+
second_thread = timer_task.instance_variable_get(:@thread)
|
|
83
|
+
expect(first_thread).to eq(second_thread)
|
|
84
|
+
timer_task.kill
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'does not execute if already killed' do
|
|
88
|
+
timer_task.instance_variable_set(:@killed, true)
|
|
89
|
+
result = timer_task.execute
|
|
90
|
+
expect(result).to eq(timer_task)
|
|
91
|
+
expect(timer_task.instance_variable_get(:@thread)).to be_nil
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
describe '#kill' do
|
|
96
|
+
it 'returns true when successfully killed' do
|
|
97
|
+
timer_task.execute
|
|
98
|
+
expect(timer_task.kill).to be true
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'returns false when already killed' do
|
|
102
|
+
timer_task.execute
|
|
103
|
+
timer_task.kill
|
|
104
|
+
expect(timer_task.kill).to be false
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'sets @killed to true' do
|
|
108
|
+
timer_task.execute
|
|
109
|
+
timer_task.kill
|
|
110
|
+
expect(timer_task.instance_variable_get(:@killed)).to be true
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'sets @running to false' do
|
|
114
|
+
timer_task.execute
|
|
115
|
+
timer_task.kill
|
|
116
|
+
expect(timer_task.instance_variable_get(:@running)).to be false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'kills the thread if alive' do
|
|
120
|
+
timer_task.execute
|
|
121
|
+
thread = timer_task.instance_variable_get(:@thread)
|
|
122
|
+
timer_task.kill
|
|
123
|
+
sleep(0.01) # Give time for thread to be killed
|
|
124
|
+
expect(thread.alive?).to be false
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'is safe to call multiple times' do
|
|
128
|
+
timer_task.execute
|
|
129
|
+
expect { timer_task.kill }.not_to raise_error
|
|
130
|
+
expect { timer_task.kill }.not_to raise_error
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'handles case when thread is nil' do
|
|
134
|
+
timer = described_class.new(execution_interval: 1) {}
|
|
135
|
+
result = nil
|
|
136
|
+
expect { result = timer.kill }.not_to raise_error
|
|
137
|
+
expect(result).to be true
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe 'execution behavior' do
|
|
142
|
+
it 'executes the task at the specified interval' do
|
|
143
|
+
execution_count = 0
|
|
144
|
+
timer = described_class.new(execution_interval: 0.05) do
|
|
145
|
+
execution_count += 1
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
timer.execute
|
|
149
|
+
sleep(0.15) # Should allow for ~3 executions
|
|
150
|
+
timer.kill
|
|
151
|
+
|
|
152
|
+
expect(execution_count).to be >= 2
|
|
153
|
+
expect(execution_count).to be <= 4 # Allow some timing variance
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'calls the task block correctly' do
|
|
157
|
+
task_called = false
|
|
158
|
+
timer = described_class.new(execution_interval: 0.05) do
|
|
159
|
+
task_called = true
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
timer.execute
|
|
163
|
+
sleep(0.1)
|
|
164
|
+
timer.kill
|
|
165
|
+
|
|
166
|
+
expect(task_called).to be true
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'handles exceptions in the task gracefully' do
|
|
170
|
+
error_count = 0
|
|
171
|
+
timer = described_class.new(execution_interval: 0.05) do
|
|
172
|
+
error_count += 1
|
|
173
|
+
raise StandardError, 'Test error'
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Capture stderr to check for error messages
|
|
177
|
+
original_stderr = $stderr
|
|
178
|
+
captured_stderr = StringIO.new
|
|
179
|
+
$stderr = captured_stderr
|
|
180
|
+
|
|
181
|
+
# Mock warn method to prevent warning gem from raising exceptions
|
|
182
|
+
# but still capture the output
|
|
183
|
+
allow_any_instance_of(Object).to receive(:warn) do |*args|
|
|
184
|
+
captured_stderr.puts(*args)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
timer.execute
|
|
188
|
+
sleep(0.15)
|
|
189
|
+
timer.kill
|
|
190
|
+
|
|
191
|
+
error_output = captured_stderr.string
|
|
192
|
+
$stderr = original_stderr
|
|
193
|
+
|
|
194
|
+
expect(error_count).to be >= 2
|
|
195
|
+
expect(error_output).to include('Test error')
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'continues execution after exceptions' do
|
|
199
|
+
execution_count = 0
|
|
200
|
+
timer = described_class.new(execution_interval: 0.05) do
|
|
201
|
+
execution_count += 1
|
|
202
|
+
raise StandardError, 'Test error' if execution_count == 1
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Mock warn method to prevent warning gem from raising exceptions
|
|
206
|
+
allow_any_instance_of(Object).to receive(:warn)
|
|
207
|
+
|
|
208
|
+
timer.execute
|
|
209
|
+
sleep(0.15)
|
|
210
|
+
timer.kill
|
|
211
|
+
|
|
212
|
+
expect(execution_count).to be >= 2 # Should continue after first error
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it 'stops execution when killed' do
|
|
216
|
+
execution_count = 0
|
|
217
|
+
timer = described_class.new(execution_interval: 0.05) do
|
|
218
|
+
execution_count += 1
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
timer.execute
|
|
222
|
+
sleep(0.1)
|
|
223
|
+
initial_count = execution_count
|
|
224
|
+
timer.kill
|
|
225
|
+
sleep(0.1)
|
|
226
|
+
final_count = execution_count
|
|
227
|
+
|
|
228
|
+
expect(final_count).to eq(initial_count)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it 'respects the execution interval' do
|
|
232
|
+
execution_times = []
|
|
233
|
+
timer = described_class.new(execution_interval: 0.1) do
|
|
234
|
+
execution_times << Time.now
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
timer.execute
|
|
238
|
+
sleep(0.35) # Allow for ~3 executions
|
|
239
|
+
timer.kill
|
|
240
|
+
|
|
241
|
+
expect(execution_times.length).to be >= 2
|
|
242
|
+
if execution_times.length >= 2
|
|
243
|
+
interval = execution_times[1] - execution_times[0]
|
|
244
|
+
expect(interval).to be_within(0.05).of(0.1)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
describe 'thread safety' do
|
|
250
|
+
it 'can be safely accessed from multiple threads' do
|
|
251
|
+
timer = described_class.new(execution_interval: 0.1) {}
|
|
252
|
+
|
|
253
|
+
threads = 10.times.map do
|
|
254
|
+
Thread.new do
|
|
255
|
+
timer.execute
|
|
256
|
+
sleep(0.01)
|
|
257
|
+
timer.kill
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
threads.each(&:join)
|
|
262
|
+
# Timer should be stopped after all threads complete
|
|
263
|
+
expect(timer.instance_variable_get(:@killed)).to be true
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it 'handles concurrent execute calls safely' do
|
|
267
|
+
timer = described_class.new(execution_interval: 0.1) {}
|
|
268
|
+
|
|
269
|
+
threads = 5.times.map do
|
|
270
|
+
Thread.new { timer.execute }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
threads.each(&:join)
|
|
274
|
+
|
|
275
|
+
# Should only have one thread created
|
|
276
|
+
expect(timer.instance_variable_get(:@thread)).to be_a(Thread)
|
|
277
|
+
timer.kill
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it 'handles concurrent kill calls safely' do
|
|
281
|
+
timer = described_class.new(execution_interval: 0.1) {}
|
|
282
|
+
timer.execute
|
|
283
|
+
|
|
284
|
+
threads = 5.times.map do
|
|
285
|
+
Thread.new { timer.kill }
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
results = threads.map(&:value)
|
|
289
|
+
|
|
290
|
+
# Only one kill should return true, others should return false
|
|
291
|
+
true_count = results.count(true)
|
|
292
|
+
false_count = results.count(false)
|
|
293
|
+
|
|
294
|
+
expect(true_count).to eq(1)
|
|
295
|
+
expect(false_count).to eq(4)
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
@@ -101,4 +101,26 @@ RSpec.describe Shoryuken::Launcher do
|
|
|
101
101
|
expect(second_group_manager).to have_received(:stop_new_dispatching)
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
|
+
|
|
105
|
+
describe '#stopping?' do
|
|
106
|
+
it 'returns false by default' do
|
|
107
|
+
expect(subject.stopping?).to be false
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it 'returns true after stop is called' do
|
|
111
|
+
allow(first_group_manager).to receive(:stop_new_dispatching)
|
|
112
|
+
allow(first_group_manager).to receive(:await_dispatching_in_progress)
|
|
113
|
+
allow(second_group_manager).to receive(:stop_new_dispatching)
|
|
114
|
+
allow(second_group_manager).to receive(:await_dispatching_in_progress)
|
|
115
|
+
|
|
116
|
+
expect { subject.stop }.to change { subject.stopping? }.from(false).to(true)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'returns true after stop! is called' do
|
|
120
|
+
allow(first_group_manager).to receive(:stop_new_dispatching)
|
|
121
|
+
allow(second_group_manager).to receive(:stop_new_dispatching)
|
|
122
|
+
|
|
123
|
+
expect { subject.stop! }.to change { subject.stopping? }.from(false).to(true)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
104
126
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shoryuken
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 7.0.0.
|
|
4
|
+
version: 7.0.0.rc1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pablo Cantero
|
|
@@ -152,10 +152,9 @@ files:
|
|
|
152
152
|
- examples/bootstrap_queues.rb
|
|
153
153
|
- examples/default_worker.rb
|
|
154
154
|
- gemfiles/.gitignore
|
|
155
|
-
- gemfiles/rails_7_0.gemfile
|
|
156
|
-
- gemfiles/rails_7_1.gemfile
|
|
157
155
|
- gemfiles/rails_7_2.gemfile
|
|
158
156
|
- gemfiles/rails_8_0.gemfile
|
|
157
|
+
- gemfiles/rails_8_1.gemfile
|
|
159
158
|
- lib/shoryuken.rb
|
|
160
159
|
- lib/shoryuken/body_parser.rb
|
|
161
160
|
- lib/shoryuken/client.rb
|
|
@@ -171,12 +170,17 @@ files:
|
|
|
171
170
|
- lib/shoryuken/helpers/atomic_hash.rb
|
|
172
171
|
- lib/shoryuken/helpers/hash_utils.rb
|
|
173
172
|
- lib/shoryuken/helpers/string_utils.rb
|
|
173
|
+
- lib/shoryuken/helpers/timer_task.rb
|
|
174
174
|
- lib/shoryuken/inline_message.rb
|
|
175
175
|
- lib/shoryuken/launcher.rb
|
|
176
176
|
- lib/shoryuken/logging.rb
|
|
177
|
+
- lib/shoryuken/logging/base.rb
|
|
178
|
+
- lib/shoryuken/logging/pretty.rb
|
|
179
|
+
- lib/shoryuken/logging/without_timestamp.rb
|
|
177
180
|
- lib/shoryuken/manager.rb
|
|
178
181
|
- lib/shoryuken/message.rb
|
|
179
182
|
- lib/shoryuken/middleware/chain.rb
|
|
183
|
+
- lib/shoryuken/middleware/entry.rb
|
|
180
184
|
- lib/shoryuken/middleware/server/active_record.rb
|
|
181
185
|
- lib/shoryuken/middleware/server/auto_delete.rb
|
|
182
186
|
- lib/shoryuken/middleware/server/auto_extend_visibility.rb
|
|
@@ -198,6 +202,7 @@ files:
|
|
|
198
202
|
- lib/shoryuken/worker_registry.rb
|
|
199
203
|
- renovate.json
|
|
200
204
|
- shoryuken.gemspec
|
|
205
|
+
- spec/integration/active_job_continuation_spec.rb
|
|
201
206
|
- spec/integration/launcher_spec.rb
|
|
202
207
|
- spec/shared_examples_for_active_job.rb
|
|
203
208
|
- spec/shoryuken.yml
|
|
@@ -209,6 +214,7 @@ files:
|
|
|
209
214
|
- spec/shoryuken/extensions/active_job_adapter_spec.rb
|
|
210
215
|
- spec/shoryuken/extensions/active_job_base_spec.rb
|
|
211
216
|
- spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb
|
|
217
|
+
- spec/shoryuken/extensions/active_job_continuation_spec.rb
|
|
212
218
|
- spec/shoryuken/extensions/active_job_wrapper_spec.rb
|
|
213
219
|
- spec/shoryuken/fetcher_spec.rb
|
|
214
220
|
- spec/shoryuken/helpers/atomic_boolean_spec.rb
|
|
@@ -216,6 +222,7 @@ files:
|
|
|
216
222
|
- spec/shoryuken/helpers/atomic_hash_spec.rb
|
|
217
223
|
- spec/shoryuken/helpers/hash_utils_spec.rb
|
|
218
224
|
- spec/shoryuken/helpers/string_utils_spec.rb
|
|
225
|
+
- spec/shoryuken/helpers/timer_task_spec.rb
|
|
219
226
|
- spec/shoryuken/helpers_integration_spec.rb
|
|
220
227
|
- spec/shoryuken/inline_message_spec.rb
|
|
221
228
|
- spec/shoryuken/launcher_spec.rb
|
|
@@ -263,6 +270,7 @@ rubygems_version: 3.6.9
|
|
|
263
270
|
specification_version: 4
|
|
264
271
|
summary: Shoryuken is a super efficient AWS SQS thread based message processor
|
|
265
272
|
test_files:
|
|
273
|
+
- spec/integration/active_job_continuation_spec.rb
|
|
266
274
|
- spec/integration/launcher_spec.rb
|
|
267
275
|
- spec/shared_examples_for_active_job.rb
|
|
268
276
|
- spec/shoryuken.yml
|
|
@@ -274,6 +282,7 @@ test_files:
|
|
|
274
282
|
- spec/shoryuken/extensions/active_job_adapter_spec.rb
|
|
275
283
|
- spec/shoryuken/extensions/active_job_base_spec.rb
|
|
276
284
|
- spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb
|
|
285
|
+
- spec/shoryuken/extensions/active_job_continuation_spec.rb
|
|
277
286
|
- spec/shoryuken/extensions/active_job_wrapper_spec.rb
|
|
278
287
|
- spec/shoryuken/fetcher_spec.rb
|
|
279
288
|
- spec/shoryuken/helpers/atomic_boolean_spec.rb
|
|
@@ -281,6 +290,7 @@ test_files:
|
|
|
281
290
|
- spec/shoryuken/helpers/atomic_hash_spec.rb
|
|
282
291
|
- spec/shoryuken/helpers/hash_utils_spec.rb
|
|
283
292
|
- spec/shoryuken/helpers/string_utils_spec.rb
|
|
293
|
+
- spec/shoryuken/helpers/timer_task_spec.rb
|
|
284
294
|
- spec/shoryuken/helpers_integration_spec.rb
|
|
285
295
|
- spec/shoryuken/inline_message_spec.rb
|
|
286
296
|
- spec/shoryuken/launcher_spec.rb
|
data/gemfiles/rails_7_0.gemfile
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# This file was generated by Appraisal
|
|
2
|
-
|
|
3
|
-
source 'https://rubygems.org'
|
|
4
|
-
|
|
5
|
-
group :test do
|
|
6
|
-
gem 'activejob', '~> 7.0'
|
|
7
|
-
gem 'httparty'
|
|
8
|
-
gem 'multi_xml'
|
|
9
|
-
gem 'simplecov'
|
|
10
|
-
gem 'warning'
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
group :development do
|
|
14
|
-
gem 'appraisal', git: 'https://github.com/thoughtbot/appraisal.git'
|
|
15
|
-
gem 'pry-byebug'
|
|
16
|
-
gem 'rubocop'
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
gemspec path: '../'
|
data/gemfiles/rails_7_1.gemfile
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# This file was generated by Appraisal
|
|
2
|
-
|
|
3
|
-
source 'https://rubygems.org'
|
|
4
|
-
|
|
5
|
-
group :test do
|
|
6
|
-
gem 'activejob', '~> 7.1'
|
|
7
|
-
gem 'httparty'
|
|
8
|
-
gem 'multi_xml'
|
|
9
|
-
gem 'simplecov'
|
|
10
|
-
gem 'warning'
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
group :development do
|
|
14
|
-
gem 'appraisal', git: 'https://github.com/thoughtbot/appraisal.git'
|
|
15
|
-
gem 'pry-byebug'
|
|
16
|
-
gem 'rubocop'
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
gemspec path: '../'
|