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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +20 -0
  3. data/.rubocop.yml +8 -2
  4. data/.travis.yml +7 -5
  5. data/CHANGELOG.md +92 -10
  6. data/Gemfile +1 -0
  7. data/README.md +20 -57
  8. data/Rakefile +0 -1
  9. data/bin/cli/base.rb +42 -0
  10. data/bin/cli/sqs.rb +188 -0
  11. data/bin/shoryuken +47 -9
  12. data/examples/default_worker.rb +1 -12
  13. data/lib/shoryuken/client.rb +3 -25
  14. data/lib/shoryuken/default_worker_registry.rb +9 -5
  15. data/lib/shoryuken/environment_loader.rb +29 -67
  16. data/lib/shoryuken/fetcher.rb +22 -53
  17. data/lib/shoryuken/launcher.rb +5 -29
  18. data/lib/shoryuken/manager.rb +72 -184
  19. data/lib/shoryuken/message.rb +4 -13
  20. data/lib/shoryuken/middleware/chain.rb +1 -18
  21. data/lib/shoryuken/middleware/server/auto_extend_visibility.rb +21 -18
  22. data/lib/shoryuken/middleware/server/exponential_backoff_retry.rb +26 -19
  23. data/lib/shoryuken/polling.rb +204 -0
  24. data/lib/shoryuken/processor.rb +6 -14
  25. data/lib/shoryuken/queue.rb +36 -38
  26. data/lib/shoryuken/runner.rb +143 -0
  27. data/lib/shoryuken/util.rb +3 -9
  28. data/lib/shoryuken/version.rb +1 -1
  29. data/lib/shoryuken/worker.rb +1 -1
  30. data/lib/shoryuken.rb +78 -39
  31. data/shoryuken.gemspec +6 -6
  32. data/spec/integration/launcher_spec.rb +4 -3
  33. data/spec/shoryuken/client_spec.rb +2 -43
  34. data/spec/shoryuken/default_worker_registry_spec.rb +12 -10
  35. data/spec/shoryuken/environment_loader_spec.rb +34 -0
  36. data/spec/shoryuken/fetcher_spec.rb +18 -52
  37. data/spec/shoryuken/manager_spec.rb +56 -97
  38. data/spec/shoryuken/middleware/chain_spec.rb +0 -24
  39. data/spec/shoryuken/middleware/server/auto_delete_spec.rb +2 -2
  40. data/spec/shoryuken/middleware/server/auto_extend_visibility_spec.rb +7 -3
  41. data/spec/shoryuken/middleware/server/exponential_backoff_retry_spec.rb +56 -33
  42. data/spec/shoryuken/polling_spec.rb +239 -0
  43. data/spec/shoryuken/processor_spec.rb +5 -5
  44. data/spec/shoryuken/queue_spec.rb +110 -63
  45. data/spec/shoryuken/{cli_spec.rb → runner_spec.rb} +10 -24
  46. data/spec/shoryuken_spec.rb +13 -1
  47. data/spec/spec_helper.rb +8 -20
  48. data/test_workers/endless_interruptive_worker.rb +41 -0
  49. data/test_workers/endless_uninterruptive_worker.rb +44 -0
  50. metadata +34 -35
  51. data/.hound.yml +0 -6
  52. data/lib/shoryuken/cli.rb +0 -210
  53. data/lib/shoryuken/sns_arn.rb +0 -27
  54. data/lib/shoryuken/topic.rb +0 -17
  55. data/spec/shoryuken/sns_arn_spec.rb +0 -42
  56. data/spec/shoryuken/topic_spec.rb +0 -32
  57. data/spec/shoryuken_endpoint.yml +0 -6
  58. /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
@@ -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
@@ -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
@@ -1,6 +0,0 @@
1
- aws:
2
- access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
3
- secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
4
- region: us-east-1
5
- sqs_endpoint: https://github.com/phstc/shoryuken:4568
6
- sns_endpoint: http://127.0.0.1:4568
File without changes