shoryuken 2.0.11 → 3.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/.codeclimate.yml +20 -0
- data/.rubocop.yml +8 -2
- data/.travis.yml +7 -5
- data/CHANGELOG.md +92 -10
- data/Gemfile +1 -0
- data/README.md +20 -57
- data/Rakefile +0 -1
- data/bin/cli/base.rb +42 -0
- data/bin/cli/sqs.rb +188 -0
- data/bin/shoryuken +47 -9
- data/examples/default_worker.rb +1 -12
- data/lib/shoryuken/client.rb +3 -25
- data/lib/shoryuken/default_worker_registry.rb +9 -5
- data/lib/shoryuken/environment_loader.rb +29 -67
- data/lib/shoryuken/fetcher.rb +22 -53
- data/lib/shoryuken/launcher.rb +5 -29
- data/lib/shoryuken/manager.rb +72 -184
- data/lib/shoryuken/message.rb +4 -13
- data/lib/shoryuken/middleware/chain.rb +1 -18
- data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +21 -18
- data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +26 -19
- data/lib/shoryuken/polling.rb +204 -0
- data/lib/shoryuken/processor.rb +6 -14
- data/lib/shoryuken/queue.rb +36 -38
- data/lib/shoryuken/runner.rb +143 -0
- data/lib/shoryuken/util.rb +3 -9
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken/worker.rb +1 -1
- data/lib/shoryuken.rb +78 -39
- data/shoryuken.gemspec +6 -6
- data/spec/integration/launcher_spec.rb +4 -3
- data/spec/shoryuken/client_spec.rb +2 -43
- data/spec/shoryuken/default_worker_registry_spec.rb +12 -10
- data/spec/shoryuken/environment_loader_spec.rb +34 -0
- data/spec/shoryuken/fetcher_spec.rb +18 -52
- data/spec/shoryuken/manager_spec.rb +56 -97
- data/spec/shoryuken/middleware/chain_spec.rb +0 -24
- data/spec/shoryuken/middleware/server/auto_delete_spec.rb +2 -2
- data/spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb +7 -3
- data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +56 -33
- data/spec/shoryuken/polling_spec.rb +239 -0
- data/spec/shoryuken/processor_spec.rb +5 -5
- data/spec/shoryuken/queue_spec.rb +110 -63
- data/spec/shoryuken/{cli_spec.rb → runner_spec.rb} +10 -24
- data/spec/shoryuken_spec.rb +13 -1
- data/spec/spec_helper.rb +8 -20
- data/test_workers/endless_interruptive_worker.rb +41 -0
- data/test_workers/endless_uninterruptive_worker.rb +44 -0
- metadata +34 -35
- data/.hound.yml +0 -6
- data/lib/shoryuken/cli.rb +0 -210
- data/lib/shoryuken/sns_arn.rb +0 -27
- data/lib/shoryuken/topic.rb +0 -17
- data/spec/shoryuken/sns_arn_spec.rb +0 -42
- data/spec/shoryuken/topic_spec.rb +0 -32
- data/spec/shoryuken_endpoint.yml +0 -6
- /data/{LICENSE.txt → LICENSE} +0 -0
data/lib/shoryuken/cli.rb
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
$stdout.sync = true
|
|
2
|
-
|
|
3
|
-
require 'singleton'
|
|
4
|
-
require 'optparse'
|
|
5
|
-
require 'erb'
|
|
6
|
-
|
|
7
|
-
require 'shoryuken'
|
|
8
|
-
|
|
9
|
-
module Shoryuken
|
|
10
|
-
# See: https://github.com/mperham/sidekiq/blob/33f5d6b2b6c0dfaab11e5d39688cab7ebadc83ae/lib/sidekiq/cli.rb#L20
|
|
11
|
-
class Shutdown < Interrupt; end
|
|
12
|
-
|
|
13
|
-
class CLI
|
|
14
|
-
include Util
|
|
15
|
-
include Singleton
|
|
16
|
-
|
|
17
|
-
attr_accessor :launcher
|
|
18
|
-
|
|
19
|
-
def run(args)
|
|
20
|
-
self_read, self_write = IO.pipe
|
|
21
|
-
|
|
22
|
-
%w(INT TERM USR1 USR2 TTIN).each do |sig|
|
|
23
|
-
begin
|
|
24
|
-
trap sig do
|
|
25
|
-
self_write.puts(sig)
|
|
26
|
-
end
|
|
27
|
-
rescue ArgumentError
|
|
28
|
-
puts "Signal #{sig} not supported"
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
options = parse_cli_args(args)
|
|
33
|
-
|
|
34
|
-
daemonize(options)
|
|
35
|
-
write_pid(options)
|
|
36
|
-
|
|
37
|
-
EnvironmentLoader.load(options)
|
|
38
|
-
|
|
39
|
-
load_celluloid
|
|
40
|
-
|
|
41
|
-
require 'shoryuken/launcher'
|
|
42
|
-
@launcher = Shoryuken::Launcher.new
|
|
43
|
-
|
|
44
|
-
if callback = Shoryuken.start_callback
|
|
45
|
-
logger.info { 'Calling Shoryuken.on_start block' }
|
|
46
|
-
callback.call
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
fire_event(:startup)
|
|
50
|
-
|
|
51
|
-
begin
|
|
52
|
-
launcher.run
|
|
53
|
-
|
|
54
|
-
while (readable_io = IO.select([self_read]))
|
|
55
|
-
signal = readable_io.first[0].gets.strip
|
|
56
|
-
handle_signal(signal)
|
|
57
|
-
end
|
|
58
|
-
rescue Interrupt
|
|
59
|
-
launcher.stop(shutdown: true)
|
|
60
|
-
exit 0
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
private
|
|
65
|
-
|
|
66
|
-
def load_celluloid
|
|
67
|
-
require 'celluloid/autostart'
|
|
68
|
-
Celluloid.logger = (Shoryuken.options[:verbose] ? Shoryuken.logger : nil)
|
|
69
|
-
|
|
70
|
-
require 'shoryuken/manager'
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def celluloid_loaded?
|
|
74
|
-
defined?(::Celluloid)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def daemonize(options)
|
|
78
|
-
return unless options[:daemon]
|
|
79
|
-
|
|
80
|
-
fail ArgumentError, "You really should set a logfile if you're going to daemonize" unless options[:logfile]
|
|
81
|
-
|
|
82
|
-
if celluloid_loaded?
|
|
83
|
-
# Celluloid can't be loaded until after we've daemonized
|
|
84
|
-
# because it spins up threads and creates locks which get
|
|
85
|
-
# into a very bad state if forked.
|
|
86
|
-
raise "Celluloid cannot be required until here, or it will break Shoryuken's daemonization"
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
files_to_reopen = []
|
|
90
|
-
ObjectSpace.each_object(File) do |file|
|
|
91
|
-
files_to_reopen << file unless file.closed?
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
Process.daemon(true, true)
|
|
95
|
-
|
|
96
|
-
files_to_reopen.each do |file|
|
|
97
|
-
begin
|
|
98
|
-
file.reopen file.path, 'a+'
|
|
99
|
-
file.sync = true
|
|
100
|
-
rescue ::Exception
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
[$stdout, $stderr].each do |io|
|
|
105
|
-
File.open(options[:logfile], 'ab') do |f|
|
|
106
|
-
io.reopen(f)
|
|
107
|
-
end
|
|
108
|
-
io.sync = true
|
|
109
|
-
end
|
|
110
|
-
$stdin.reopen('/dev/null')
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def write_pid(options)
|
|
114
|
-
if (path = options[:pidfile])
|
|
115
|
-
File.open(path, 'w') do |f|
|
|
116
|
-
f.puts Process.pid
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def parse_cli_args(argv)
|
|
122
|
-
opts = {}
|
|
123
|
-
|
|
124
|
-
@parser = OptionParser.new do |o|
|
|
125
|
-
o.on '-c', '--concurrency INT', 'Processor threads to use' do |arg|
|
|
126
|
-
opts[:concurrency] = Integer(arg)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
o.on '-d', '--daemon', 'Daemonize process' do |arg|
|
|
130
|
-
opts[:daemon] = arg
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
o.on '-q', '--queue QUEUE[,WEIGHT]...', 'Queues to process with optional weights' do |arg|
|
|
134
|
-
queue, weight = arg.split(',')
|
|
135
|
-
opts[:queues] = [] unless opts[:queues]
|
|
136
|
-
opts[:queues] << [queue, weight]
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
o.on '-r', '--require [PATH|DIR]', 'Location of the worker' do |arg|
|
|
140
|
-
opts[:require] = arg
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
o.on '-C', '--config PATH', 'Path to YAML config file' do |arg|
|
|
144
|
-
opts[:config_file] = arg
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
o.on '-R', '--rails', 'Load Rails' do |arg|
|
|
148
|
-
opts[:rails] = arg
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
o.on '-L', '--logfile PATH', 'Path to writable logfile' do |arg|
|
|
152
|
-
opts[:logfile] = arg
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
o.on '-P', '--pidfile PATH', 'Path to pidfile' do |arg|
|
|
156
|
-
opts[:pidfile] = arg
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
o.on '-v', '--verbose', 'Print more verbose output' do |arg|
|
|
160
|
-
opts[:verbose] = arg
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
o.on '-V', '--version', 'Print version and exit' do
|
|
164
|
-
puts "Shoryuken #{Shoryuken::VERSION}"
|
|
165
|
-
exit 0
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
@parser.banner = 'shoryuken [options]'
|
|
170
|
-
@parser.on_tail '-h', '--help', 'Show help' do
|
|
171
|
-
logger.info { @parser }
|
|
172
|
-
exit 1
|
|
173
|
-
end
|
|
174
|
-
@parser.parse!(argv)
|
|
175
|
-
opts
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def handle_signal(sig)
|
|
179
|
-
logger.info { "Got #{sig} signal" }
|
|
180
|
-
|
|
181
|
-
case sig
|
|
182
|
-
when 'USR1'
|
|
183
|
-
logger.info { 'Received USR1, will soft shutdown down' }
|
|
184
|
-
|
|
185
|
-
launcher.stop
|
|
186
|
-
fire_event(:quiet, true)
|
|
187
|
-
exit 0
|
|
188
|
-
when 'TTIN'
|
|
189
|
-
Thread.list.each do |thread|
|
|
190
|
-
logger.info { "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}" }
|
|
191
|
-
if thread.backtrace
|
|
192
|
-
logger.info { thread.backtrace.join("\n") }
|
|
193
|
-
else
|
|
194
|
-
logger.info { '<no backtrace available>' }
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
ready = launcher.manager.instance_variable_get(:@ready).size
|
|
199
|
-
busy = launcher.manager.instance_variable_get(:@busy).size
|
|
200
|
-
queues = launcher.manager.instance_variable_get(:@queues)
|
|
201
|
-
|
|
202
|
-
logger.info { "Ready: #{ready}, Busy: #{busy}, Active Queues: #{unparse_queues(queues)}" }
|
|
203
|
-
else
|
|
204
|
-
logger.info { "Received #{sig}, will shutdown down" }
|
|
205
|
-
|
|
206
|
-
raise Interrupt
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
end
|
data/lib/shoryuken/sns_arn.rb
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
module Shoryuken
|
|
2
|
-
class SnsArn
|
|
3
|
-
def initialize(topic)
|
|
4
|
-
@topic = topic
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def to_s
|
|
8
|
-
@arn ||= "arn:aws:sns:#{region}:#{account_id}:#{@topic}"
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
|
|
13
|
-
def account_id
|
|
14
|
-
Shoryuken::Client.account_id.tap do |account_id|
|
|
15
|
-
if account_id.to_s.empty?
|
|
16
|
-
fail 'To generate SNS ARNs, you must assign an :account_id in your Shoryuken::Client.'
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def region
|
|
22
|
-
Aws.config.fetch(:region) do
|
|
23
|
-
fail 'To generate SNS ARNs, you must include a :region in your AWS config.'
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
data/lib/shoryuken/topic.rb
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
module Shoryuken
|
|
2
|
-
class Topic
|
|
3
|
-
def initialize(name, sns)
|
|
4
|
-
@name, @sns = name, sns
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def arn
|
|
8
|
-
@arn ||= Client.sns_arn.new(@name).to_s
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def send_message(body, options = {})
|
|
12
|
-
body = JSON.dump(body) if body.is_a?(Hash)
|
|
13
|
-
|
|
14
|
-
@sns.publish(topic_arn: arn, message: body)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Shoryuken::SnsArn do
|
|
4
|
-
let(:account_id) { '1234567890' }
|
|
5
|
-
let(:region) { 'eu-west-1' }
|
|
6
|
-
let(:topic) { 'topic-x' }
|
|
7
|
-
|
|
8
|
-
before do
|
|
9
|
-
Shoryuken::Client.account_id = account_id
|
|
10
|
-
Aws.config = { region: region }
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
subject { described_class.new(topic).to_s }
|
|
14
|
-
|
|
15
|
-
describe '#to_s' do
|
|
16
|
-
context 'when the Aws config includes all the information necessary' do
|
|
17
|
-
it 'generates an SNS arn' do
|
|
18
|
-
expect(subject).to eq('arn:aws:sns:eu-west-1:1234567890:topic-x')
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
context 'when the Aws config does not include the account id' do
|
|
23
|
-
before do
|
|
24
|
-
Shoryuken::Client.account_id = nil
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it 'fails' do
|
|
28
|
-
expect { subject }.to raise_error(/an :account_id/)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
context 'when the Aws config does not include the region' do
|
|
33
|
-
before do
|
|
34
|
-
Aws.config.delete :region
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'fails' do
|
|
38
|
-
expect { subject }.to raise_error(/a :region/)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Shoryuken::Topic do
|
|
4
|
-
let(:sns) { Aws::SNS::Client.new stub_responses: true }
|
|
5
|
-
let(:topic_arn) { 'arn:aws:sns:us-east-1:0987654321:shoryuken' }
|
|
6
|
-
let(:topic_name) { 'shoryuken' }
|
|
7
|
-
|
|
8
|
-
before do
|
|
9
|
-
Shoryuken::Client.account_id = '0987654321'
|
|
10
|
-
Aws.config = { region: 'us-east-1' }
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
subject { described_class.new(topic_name, sns) }
|
|
14
|
-
|
|
15
|
-
describe '#send_message' do
|
|
16
|
-
it 'enqueues a message' do
|
|
17
|
-
sns.stub_responses(:publish, { message_id: 'msg1' })
|
|
18
|
-
expect(sns).to receive(:publish).with(topic_arn: topic_arn, message: 'test')
|
|
19
|
-
|
|
20
|
-
subject.send_message('test')
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it 'parses as JSON by default' do
|
|
24
|
-
msg = { field: 'test', other_field: 'other' }
|
|
25
|
-
|
|
26
|
-
sns.stub_responses(:publish, { message_id: 'msg2' })
|
|
27
|
-
expect(sns).to receive(:publish).with(topic_arn: topic_arn, message: JSON.dump(msg))
|
|
28
|
-
|
|
29
|
-
subject.send_message(msg)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
data/spec/shoryuken_endpoint.yml
DELETED
/data/{LICENSE.txt → LICENSE}
RENAMED
|
File without changes
|