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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3810f509ebbedaf23dfcd756b17f487097d99ab7
|
|
4
|
+
data.tar.gz: 2dabc0be8dbab5536377b7fe6cb6e371b1c0a71c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5fe6096c4df914e64b56dcbcad889bda4827cbf6882ab018d4e8568cab9caf61f548a6117ba3b5607da13abcad049be58c59d8498d76abcc0b6f366579eaa79d
|
|
7
|
+
data.tar.gz: 61c52ec5a273c3294679baff1b00f5938d1aec218f0a304ff7503c2c28f537407306380e8fce9e954ba4caa92113e682289a68de42dd26e3d5515f9714e30d92
|
data/.codeclimate.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
engines:
|
|
3
|
+
reek:
|
|
4
|
+
enabled: true
|
|
5
|
+
duplication:
|
|
6
|
+
enabled: true
|
|
7
|
+
config:
|
|
8
|
+
languages:
|
|
9
|
+
- ruby
|
|
10
|
+
fixme:
|
|
11
|
+
enabled: true
|
|
12
|
+
rubocop:
|
|
13
|
+
enabled: true
|
|
14
|
+
config:
|
|
15
|
+
file: .rubocop.yml
|
|
16
|
+
ratings:
|
|
17
|
+
paths:
|
|
18
|
+
- "**.rb"
|
|
19
|
+
exclude_paths:
|
|
20
|
+
- spec/
|
data/.rubocop.yml
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 2.0
|
|
3
3
|
|
|
4
4
|
Style/SignalException:
|
|
5
5
|
Enabled: false
|
|
6
6
|
|
|
7
|
+
Style/DoubleNegation:
|
|
8
|
+
Enabled: false
|
|
9
|
+
|
|
7
10
|
Style/SpaceAroundEqualsInParameterDefault:
|
|
8
11
|
Enabled: false
|
|
9
12
|
|
|
@@ -28,6 +31,9 @@ Metrics/ClassLength:
|
|
|
28
31
|
Metrics/ParameterLists:
|
|
29
32
|
Enabled: false
|
|
30
33
|
|
|
34
|
+
Metrics/LineLength:
|
|
35
|
+
Max: 120
|
|
36
|
+
|
|
31
37
|
Metrics/MethodLength :
|
|
32
38
|
Enabled: false
|
|
33
39
|
|
data/.travis.yml
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
language: ruby
|
|
2
2
|
rvm:
|
|
3
|
-
# - 1.9.3
|
|
4
|
-
# - 1.9.2
|
|
5
3
|
- 2.0.0
|
|
6
4
|
- 2.1.0
|
|
7
5
|
- 2.2.0
|
|
8
|
-
|
|
9
|
-
# - jruby-19mode
|
|
10
|
-
# - jruby-head
|
|
6
|
+
- 2.3.3
|
|
11
7
|
|
|
12
8
|
notifications:
|
|
13
9
|
email:
|
|
@@ -17,3 +13,9 @@ notifications:
|
|
|
17
13
|
script: SPEC_ALL=true bundle exec rspec spec
|
|
18
14
|
before_install:
|
|
19
15
|
- gem update bundler
|
|
16
|
+
after_success:
|
|
17
|
+
- bundle exec codeclimate-test-reporter
|
|
18
|
+
|
|
19
|
+
addons:
|
|
20
|
+
code_climate:
|
|
21
|
+
repo_token: 7709fd21981bb9d2658647a66d959415a1029a83f1c199573828797944f26c52
|
data/CHANGELOG.md
CHANGED
|
@@ -1,40 +1,122 @@
|
|
|
1
|
+
## [v3.0.0] - 2017-03-12
|
|
2
|
+
- Replace Celluloid with Concurrent Ruby
|
|
3
|
+
- [#291](https://github.com/phstc/shoryuken/pull/291)
|
|
4
|
+
|
|
5
|
+
- Remove AWS configuration from Shoryuken. Now AWS should be configured from outside. Check [this](https://github.com/phstc/shoryuken/wiki/Configure-the-AWS-Client) for more details
|
|
6
|
+
- [#317](https://github.com/phstc/shoryuken/pull/291)
|
|
7
|
+
|
|
8
|
+
- Remove deprecation warnings
|
|
9
|
+
- [#326](https://github.com/phstc/shoryuken/pull/326)
|
|
10
|
+
|
|
11
|
+
- Allow dynamic adding queues
|
|
12
|
+
- [#322](https://github.com/phstc/shoryuken/pull/326)
|
|
13
|
+
|
|
14
|
+
- Support retry_intervals passed in as a lambda. Auto coerce intervals into integer
|
|
15
|
+
- [#329](https://github.com/phstc/shoryuken/pull/329)
|
|
16
|
+
|
|
17
|
+
- Add SQS commands `shoryuken help sqs`, such `ls`, `mv`, `dump` and `requeue`
|
|
18
|
+
- [#330](https://github.com/phstc/shoryuken/pull/330)
|
|
19
|
+
|
|
20
|
+
## [v2.1.3] - 2017-01-27
|
|
21
|
+
- Show a warn message when batch isn't supported
|
|
22
|
+
- [#302](https://github.com/phstc/shoryuken/pull/302)
|
|
23
|
+
|
|
24
|
+
- Require Celluloid ~> 17
|
|
25
|
+
- [#305](https://github.com/phstc/shoryuken/pull/305)
|
|
26
|
+
|
|
27
|
+
- Fix excessive logging when 0 messages found
|
|
28
|
+
- [#307](https://github.com/phstc/shoryuken/pull/307)
|
|
29
|
+
|
|
30
|
+
## [v2.1.2] - 2016-12-22
|
|
31
|
+
- Fix loading `logfile` from shoryuken.yml
|
|
32
|
+
- [#296](https://github.com/phstc/shoryuken/pull/296)
|
|
33
|
+
|
|
34
|
+
- Add support for Strict priority polling (pending documentation)
|
|
35
|
+
- [#288](https://github.com/phstc/shoryuken/pull/288)
|
|
36
|
+
|
|
37
|
+
- Add `test_workers` for end-to-end testing supporting
|
|
38
|
+
- [#286](https://github.com/phstc/shoryuken/pull/286)
|
|
39
|
+
|
|
40
|
+
- Update README documenting `configure_client` and `configure_server`
|
|
41
|
+
- [#283](https://github.com/phstc/shoryuken/pull/283)
|
|
42
|
+
|
|
43
|
+
- Fix memory leak caused by async tracking busy threads
|
|
44
|
+
- [#289](https://github.com/phstc/shoryuken/pull/289)
|
|
45
|
+
|
|
46
|
+
- Refactor fetcher, polling strategy and manager
|
|
47
|
+
- [#284](https://github.com/phstc/shoryuken/pull/284)
|
|
48
|
+
|
|
49
|
+
## [v2.1.1] - 2016-12-05
|
|
50
|
+
- Fix aws deprecation warning message
|
|
51
|
+
- [#279](https://github.com/phstc/shoryuken/pull/279)
|
|
52
|
+
|
|
53
|
+
## [v2.1.0] - 2016-12-03
|
|
54
|
+
- Fix celluloid "running in BACKPORTED mode" warning
|
|
55
|
+
- [#260](https://github.com/phstc/shoryuken/pull/260)
|
|
56
|
+
|
|
57
|
+
- Allow setting the aws configuration in 'Shoryuken.configure_server'
|
|
58
|
+
- [#252](https://github.com/phstc/shoryuken/pull/252)
|
|
59
|
+
|
|
60
|
+
- Allow requiring a file or dir a through `-r`
|
|
61
|
+
- [#248](https://github.com/phstc/shoryuken/pull/248)
|
|
62
|
+
|
|
63
|
+
- Reduce info log verbosity
|
|
64
|
+
- [#243](https://github.com/phstc/shoryuken/pull/243)
|
|
65
|
+
|
|
66
|
+
- Fix auto extender when using ActiveJob
|
|
67
|
+
- [#3213](https://github.com/phstc/shoryuken/pull/213)
|
|
68
|
+
|
|
69
|
+
- Add FIFO queue support
|
|
70
|
+
- [#272](https://github.com/phstc/shoryuken/issues/272)
|
|
71
|
+
|
|
72
|
+
- Deprecates initialize_aws
|
|
73
|
+
- [#269](https://github.com/phstc/shoryuken/pull/269)
|
|
74
|
+
|
|
75
|
+
- [Other miscellaneous updates](https://github.com/phstc/shoryuken/compare/v2.0.11...v2.1.0)
|
|
76
|
+
|
|
77
|
+
## [v2.0.11] - 2016-07-02
|
|
78
|
+
|
|
79
|
+
- Same as 2.0.10. Unfortunately 2.0.10 was removed `yanked` by mistake from RubyGems.
|
|
80
|
+
- [#b255bc3](https://github.com/phstc/shoryuken/commit/b255bc3)
|
|
81
|
+
|
|
1
82
|
## [v2.0.10] - 2016-06-09
|
|
2
83
|
|
|
3
84
|
- Fix manager #225
|
|
4
|
-
- [#226]
|
|
85
|
+
- [#226](https://github.com/phstc/shoryuken/pull/226)
|
|
5
86
|
|
|
6
87
|
## [v2.0.9] - 2016-06-08
|
|
7
88
|
|
|
8
89
|
- Fix daemonization broken in #219
|
|
9
|
-
- [#224]
|
|
90
|
+
- [#224](https://github.com/phstc/shoryuken/pull/224)
|
|
10
91
|
|
|
11
92
|
## [v2.0.8] - 2016-06-07
|
|
12
93
|
|
|
13
94
|
- Fix daemonization
|
|
14
|
-
- [#223]
|
|
95
|
+
- [#223](https://github.com/phstc/shoryuken/pull/223)
|
|
15
96
|
|
|
16
97
|
## [v2.0.7] - 2016-06-06
|
|
17
98
|
|
|
18
99
|
- Daemonize before loading environment
|
|
19
|
-
- [#219]
|
|
100
|
+
- [#219](https://github.com/phstc/shoryuken/pull/219)
|
|
20
101
|
|
|
21
102
|
- Fix initialization when using rails
|
|
22
|
-
- [#197]
|
|
103
|
+
- [#197](https://github.com/phstc/shoryuken/pull/197)
|
|
23
104
|
|
|
24
105
|
- Improve message fetching
|
|
25
|
-
- https://github.com/phstc/shoryuken/pull/214
|
|
106
|
+
- [#214](https://github.com/phstc/shoryuken/pull/214)
|
|
107
|
+
- [#f4640d9](https://github.com/phstc/shoryuken/commit/f4640d9)
|
|
26
108
|
|
|
27
109
|
- Fix hard shutdown if there are some busy workers when signal received
|
|
28
|
-
- [#215]
|
|
110
|
+
- [#215](https://github.com/phstc/shoryuken/pull/215)
|
|
29
111
|
|
|
30
112
|
- Fix `rake console` task
|
|
31
|
-
- [#208]
|
|
113
|
+
- [#208](https://github.com/phstc/shoryuken/pull/208)
|
|
32
114
|
|
|
33
115
|
- Isolate `MessageVisibilityExtender` as new middleware
|
|
34
|
-
- [#199]
|
|
116
|
+
- [#199](https://github.com/phstc/shoryuken/pull/190)
|
|
35
117
|
|
|
36
118
|
- Fail on non-existent queues
|
|
37
|
-
- [#196]
|
|
119
|
+
- [#196](https://github.com/phstc/shoryuken/pull/196)
|
|
38
120
|
|
|
39
121
|
## [v2.0.6] - 2016-04-18
|
|
40
122
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -20,18 +20,18 @@ concurrency: 25
|
|
|
20
20
|
delay: 25
|
|
21
21
|
queues:
|
|
22
22
|
- [high_priority, 6]
|
|
23
|
-
- [
|
|
23
|
+
- [normal_priority, 2]
|
|
24
24
|
- [low_priority, 1]
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
And supposing all the queues are full of messages, the configuration above will make Shoryuken to process `high_priority` 3 times more than `
|
|
28
|
-
splitting the work among
|
|
27
|
+
And supposing all the queues are full of messages, the configuration above will make Shoryuken to process `high_priority` 3 times more than `normal_priority` and 6 times more than `low_priority`,
|
|
28
|
+
splitting the work load among all available processors `concurrency: 25` .
|
|
29
29
|
|
|
30
|
-
If `high_priority` gets empty, Shoryuken will keep using the 25 processors, but only to process `
|
|
30
|
+
If `high_priority` gets empty, Shoryuken will keep using the 25 processors, but only to process `normal_priority` and `low_priority`.
|
|
31
31
|
|
|
32
|
-
If `high_priority` receives a new message, Shoryuken will smoothly increase back
|
|
32
|
+
If `high_priority` receives a new message, Shoryuken will smoothly increase back its weight one by one until it reaches the weight of 6 again.
|
|
33
33
|
|
|
34
|
-
If
|
|
34
|
+
[If a queue gets empty, Shoryuken will pause checking it for `delay: 25`](https://github.com/phstc/shoryuken/wiki/Shoryuken-options#delay).
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
### Fetch in batches
|
|
@@ -40,7 +40,7 @@ To be even more performant and cost effective, Shoryuken fetches SQS messages in
|
|
|
40
40
|
|
|
41
41
|
## Requirements
|
|
42
42
|
|
|
43
|
-
Ruby 2.0 or greater.
|
|
43
|
+
Ruby 2.0 or greater.
|
|
44
44
|
|
|
45
45
|
## Installation
|
|
46
46
|
|
|
@@ -105,49 +105,22 @@ end
|
|
|
105
105
|
|
|
106
106
|
[Check the Middleware documentation](https://github.com/phstc/shoryuken/wiki/Middleware).
|
|
107
107
|
|
|
108
|
-
### Configuration
|
|
108
|
+
### Shoryuken Configuration
|
|
109
109
|
|
|
110
110
|
Sample configuration file `shoryuken.yml`.
|
|
111
111
|
|
|
112
112
|
```yaml
|
|
113
|
-
aws:
|
|
114
|
-
access_key_id: ... # or <%= ENV['AWS_ACCESS_KEY_ID'] %>
|
|
115
|
-
secret_access_key: ... # or <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
|
|
116
|
-
region: us-east-1 # or <%= ENV['AWS_REGION'] %>
|
|
117
|
-
receive_message: # See http://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html#receive_message-instance_method
|
|
118
|
-
# wait_time_seconds: N # The number of seconds to wait for new messages when polling. Defaults to the #wait_time_seconds defined on the queue
|
|
119
|
-
attribute_names:
|
|
120
|
-
- ApproximateReceiveCount
|
|
121
|
-
- SentTimestamp
|
|
122
113
|
concurrency: 25 # The number of allocated threads to process messages. Default 25
|
|
123
114
|
delay: 25 # The delay in seconds to pause a queue when it's empty. Default 0
|
|
124
115
|
queues:
|
|
125
116
|
- [high_priority, 6]
|
|
126
|
-
- [
|
|
117
|
+
- [normal_priority, 2]
|
|
127
118
|
- [low_priority, 1]
|
|
128
119
|
```
|
|
129
120
|
|
|
130
|
-
|
|
121
|
+
#### AWS Configuration
|
|
131
122
|
|
|
132
|
-
|
|
133
|
-
- ```sns_endpoint``` can be used to explicitly override the SNS endpoint
|
|
134
|
-
- ```sqs_endpoint``` can be used to explicitly override the SQS endpoint
|
|
135
|
-
- ```receive_message``` can be used to define the options passed to the http://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html#receive_message-instance_method
|
|
136
|
-
|
|
137
|
-
The ```sns_endpoint``` and ```sqs_endpoint``` Shoryuken-specific options will also fallback to the environment variables ```AWS_SNS_ENDPOINT``` and ```AWS_SQS_ENDPOINT``` respectively, if they are set.
|
|
138
|
-
|
|
139
|
-
### Configuration (producer side)
|
|
140
|
-
|
|
141
|
-
'Producer' processes need permissions to put messages into SQS. There are a few ways:
|
|
142
|
-
|
|
143
|
-
* Ensure the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` env vars are set.
|
|
144
|
-
* Create a `~/.aws/credentials` file.
|
|
145
|
-
* Set `Aws.config[:credentials]` from Ruby code (e.g. in a Rails initializer)
|
|
146
|
-
* Use the Instance Profiles feature. The IAM role of the targeted machine must have an adequate SQS Policy.
|
|
147
|
-
|
|
148
|
-
Note that storing your credentials into Amazon instances represents a security risk. Instance Profiles tends to be the best choice.
|
|
149
|
-
|
|
150
|
-
You can read about these in more detail [here](http://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html).
|
|
123
|
+
[Check the Configure AWS Client documentation](https://github.com/phstc/shoryuken/wiki/Configure-the-AWS-Client)
|
|
151
124
|
|
|
152
125
|
### Rails Integration
|
|
153
126
|
|
|
@@ -159,26 +132,16 @@ You can read about these in more detail [here](http://docs.aws.amazon.com/sdkfor
|
|
|
159
132
|
bundle exec shoryuken -r worker.rb -C shoryuken.yml
|
|
160
133
|
```
|
|
161
134
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
shoryuken [options]
|
|
168
|
-
-c, --concurrency INT Processor threads to use
|
|
169
|
-
-d, --daemon Daemonize process
|
|
170
|
-
-q, --queue QUEUE[,WEIGHT]... Queues to process with optional weights
|
|
171
|
-
-r, --require [PATH|DIR] Location of the worker
|
|
172
|
-
-C, --config PATH Path to YAML config file
|
|
173
|
-
-R, --rails Attempts to load the containing Rails project
|
|
174
|
-
-L, --logfile PATH Path to writable logfile
|
|
175
|
-
-P, --pidfile PATH Path to pidfile
|
|
176
|
-
-v, --verbose Print more verbose output
|
|
177
|
-
-V, --version Print version and exit
|
|
178
|
-
-h, --help Show help
|
|
179
|
-
...
|
|
180
|
-
```
|
|
135
|
+
For other options check `bundle exec shoryuken help start`
|
|
136
|
+
|
|
137
|
+
#### SQS commands
|
|
138
|
+
|
|
139
|
+
Check also some available SQS commands `bundle exec shoryuken help sqs`, such as:
|
|
181
140
|
|
|
141
|
+
- `ls` list queues
|
|
142
|
+
- `mv` move messages from one queue to another
|
|
143
|
+
- `dump` dump messages from a queue into a JSON lines file
|
|
144
|
+
- `requeue` requeue messages from a dump file
|
|
182
145
|
|
|
183
146
|
## More Information
|
|
184
147
|
|
data/Rakefile
CHANGED
data/bin/cli/base.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# rubocop:disable Metrics/BlockLength
|
|
2
|
+
module Shoryuken
|
|
3
|
+
module CLI
|
|
4
|
+
class Base < Thor
|
|
5
|
+
no_commands do
|
|
6
|
+
def print_table(entries)
|
|
7
|
+
column_sizes = print_columns_size(entries)
|
|
8
|
+
|
|
9
|
+
entries.map do |entry|
|
|
10
|
+
puts entry.map.with_index { |e, i| print_format_column(e, column_sizes[i]) }.join
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def print_columns_size(entries)
|
|
15
|
+
column_sizes = Hash.new(0)
|
|
16
|
+
|
|
17
|
+
entries.each do |entry|
|
|
18
|
+
entry.each_with_index do |e, i|
|
|
19
|
+
e = e.to_s
|
|
20
|
+
column_sizes[i] = e.size if column_sizes[i] < e.size
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
column_sizes
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def print_format_column(column, size)
|
|
28
|
+
size = 40 if size > 40
|
|
29
|
+
size_with_padding = size + 4
|
|
30
|
+
column = column.to_s.ljust(size_with_padding)
|
|
31
|
+
column = "#{column[0...size - 2]}.." if column.size > size_with_padding
|
|
32
|
+
column
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def fail_task(msg, quit = true)
|
|
36
|
+
say "[FAIL] #{msg}", :red
|
|
37
|
+
exit(1) if quit
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/bin/cli/sqs.rb
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/AbcSize, Metrics/BlockLength
|
|
4
|
+
module Shoryuken
|
|
5
|
+
module CLI
|
|
6
|
+
class SQS < Base
|
|
7
|
+
namespace :sqs
|
|
8
|
+
|
|
9
|
+
no_commands do
|
|
10
|
+
def normalize_dump_message(message)
|
|
11
|
+
message[:id] = message.delete(:message_id)
|
|
12
|
+
message[:message_body] = message.delete(:body)
|
|
13
|
+
message.delete(:receipt_handle)
|
|
14
|
+
message.delete(:md5_of_body)
|
|
15
|
+
message.delete(:md5_of_message_attributes)
|
|
16
|
+
message
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def sqs
|
|
20
|
+
@_sqs ||= Aws::SQS::Client.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def find_queue_url(queue_name_prefix)
|
|
24
|
+
urls = sqs.list_queues(queue_name_prefix: queue_name_prefix).queue_urls
|
|
25
|
+
|
|
26
|
+
if urls.size > 1
|
|
27
|
+
fail_task "There's more than one queue starting with #{queue_name_prefix}: #{urls.join(', ')}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
url = urls.first
|
|
31
|
+
|
|
32
|
+
fail_task "Queue #{queue_name_prefix} not found" unless url
|
|
33
|
+
|
|
34
|
+
url
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def batch_delete(url, messages)
|
|
38
|
+
messages.to_a.flatten.each_slice(10) do |batch|
|
|
39
|
+
sqs.delete_message_batch(
|
|
40
|
+
queue_url: url,
|
|
41
|
+
entries: batch.map { |message| { id: message.message_id, receipt_handle: message.receipt_handle } }
|
|
42
|
+
).failed.any? do |failure|
|
|
43
|
+
say "Could not delete #{failure.id}, code: #{failure.code}", :yellow
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def batch_send(url, messages)
|
|
49
|
+
messages.to_a.flatten.map(&method(:normalize_dump_message)).each_slice(10) do |batch|
|
|
50
|
+
sqs.send_message_batch(queue_url: url, entries: batch).failed.any? do |failure|
|
|
51
|
+
say "Could not requeue #{failure.id}, code: #{failure.code}", :yellow
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def find_all(url, limit, &block)
|
|
57
|
+
count = 0
|
|
58
|
+
batch_size = limit > 10 ? 10 : limit
|
|
59
|
+
|
|
60
|
+
loop do
|
|
61
|
+
n = limit - count
|
|
62
|
+
batch_size = n if n < batch_size
|
|
63
|
+
|
|
64
|
+
messages = sqs.receive_message(
|
|
65
|
+
queue_url: url,
|
|
66
|
+
max_number_of_messages: batch_size,
|
|
67
|
+
message_attribute_names: ['All']
|
|
68
|
+
).messages
|
|
69
|
+
|
|
70
|
+
messages.each { |m| yield m }
|
|
71
|
+
|
|
72
|
+
count += messages.size
|
|
73
|
+
|
|
74
|
+
break if count >= limit
|
|
75
|
+
break if messages.empty?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
count
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def list_and_print_queues(urls)
|
|
82
|
+
attrs = %w(QueueArn ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible LastModifiedTimestamp)
|
|
83
|
+
|
|
84
|
+
entries = urls.map { |u| sqs.get_queue_attributes(queue_url: u, attribute_names: attrs).attributes }.map do |q|
|
|
85
|
+
[
|
|
86
|
+
q['QueueArn'].split(':').last,
|
|
87
|
+
q['ApproximateNumberOfMessages'],
|
|
88
|
+
q['ApproximateNumberOfMessagesNotVisible'],
|
|
89
|
+
Time.at(q['LastModifiedTimestamp'].to_i)
|
|
90
|
+
]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
entries.unshift(['Queue', 'Messages Available', 'Messages Inflight', 'Last Modified'])
|
|
94
|
+
|
|
95
|
+
print_table(entries)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def dump_file(path, queue_name)
|
|
99
|
+
File.join(path, "#{queue_name}-#{Date.today}.jsonl")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
desc 'ls [QUEUE-NAME-PREFIX]', 'List queues'
|
|
104
|
+
method_option :watch, aliases: '-w', type: :boolean, desc: 'watch queues'
|
|
105
|
+
method_option :watch_interval, type: :numeric, default: 10, desc: 'watch interval'
|
|
106
|
+
def ls(queue_name_prefix = '')
|
|
107
|
+
trap('SIGINT', 'EXIT') # expect ctrl-c from loop
|
|
108
|
+
|
|
109
|
+
urls = sqs.list_queues(queue_name_prefix: queue_name_prefix).queue_urls
|
|
110
|
+
|
|
111
|
+
loop do
|
|
112
|
+
list_and_print_queues(urls)
|
|
113
|
+
|
|
114
|
+
break unless options.watch
|
|
115
|
+
|
|
116
|
+
sleep options.watch_interval
|
|
117
|
+
puts
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
desc 'dump QUEUE-NAME', 'Dump messages from a queue into a JSON lines file'
|
|
122
|
+
method_option :number, aliases: '-n', type: :numeric, default: Float::INFINITY, desc: 'number of messages to dump'
|
|
123
|
+
method_option :path, aliases: '-p', type: :string, default: './', desc: 'path to save the dump file'
|
|
124
|
+
method_option :delete, aliases: '-d', type: :boolean, default: true, desc: 'delete from the queue'
|
|
125
|
+
def dump(queue_name)
|
|
126
|
+
path = dump_file(options.path, queue_name)
|
|
127
|
+
|
|
128
|
+
fail_task "File #{path} already exists" if File.exist?(path)
|
|
129
|
+
|
|
130
|
+
url = find_queue_url(queue_name)
|
|
131
|
+
|
|
132
|
+
messages = []
|
|
133
|
+
|
|
134
|
+
file = nil
|
|
135
|
+
|
|
136
|
+
count = find_all(url, options.number) do |m|
|
|
137
|
+
file ||= File.open(path, 'w')
|
|
138
|
+
|
|
139
|
+
file.puts(JSON.dump(m.to_h))
|
|
140
|
+
|
|
141
|
+
messages << m if options.delete
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
batch_delete(url, messages) if options.delete
|
|
145
|
+
|
|
146
|
+
if count.zero?
|
|
147
|
+
say "Queue #{queue_name} is empty", :yellow
|
|
148
|
+
else
|
|
149
|
+
say "Dump saved in #{path} with #{count} messages", :green
|
|
150
|
+
end
|
|
151
|
+
ensure
|
|
152
|
+
file.close if file
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
desc 'requeue QUEUE-NAME PATH', 'Requeue messages from a dump file'
|
|
156
|
+
def requeue(queue_name, path)
|
|
157
|
+
fail_task "Path #{path} not found" unless File.exist?(path)
|
|
158
|
+
|
|
159
|
+
messages = File.readlines(path).map { |line| JSON.parse(line, symbolize_names: true) }
|
|
160
|
+
|
|
161
|
+
batch_send(find_queue_url(queue_name), messages)
|
|
162
|
+
|
|
163
|
+
say "Requeued #{messages.size} messages from #{path} to #{queue_name}", :green
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
desc 'mv QUEUE-NAME-SOURCE QUEUE-NAME-TARGET', 'Move messages from one queue (source) to another (target)'
|
|
167
|
+
method_option :number, aliases: '-n', type: :numeric, default: Float::INFINITY, desc: 'number of messages to move'
|
|
168
|
+
method_option :delete, aliases: '-d', type: :boolean, default: true, desc: 'delete from the queue'
|
|
169
|
+
def mv(queue_name_source, queue_name_target)
|
|
170
|
+
url_source = find_queue_url(queue_name_source)
|
|
171
|
+
messages = []
|
|
172
|
+
|
|
173
|
+
count = find_all(url_source, options.number) do |m|
|
|
174
|
+
messages << m
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
batch_send(find_queue_url(queue_name_target), messages.map(&:to_h))
|
|
178
|
+
batch_delete(url_source, messages) if options.delete
|
|
179
|
+
|
|
180
|
+
if count.zero?
|
|
181
|
+
say "Queue #{queue_name_source} is empty", :yellow
|
|
182
|
+
else
|
|
183
|
+
say "Moved #{count} messages from #{queue_name_source} to #{queue_name_target}", :green
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
data/bin/shoryuken
CHANGED
|
@@ -1,12 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
|
|
5
|
+
require 'thor'
|
|
6
|
+
require 'aws-sdk-core'
|
|
7
|
+
require_relative 'cli/base'
|
|
8
|
+
require_relative 'cli/sqs'
|
|
9
|
+
require_relative '../lib/shoryuken/runner'
|
|
10
|
+
|
|
11
|
+
# rubocop:disable Metrics/AbcSize
|
|
12
|
+
module Shoryuken
|
|
13
|
+
module CLI
|
|
14
|
+
class Runner < Base
|
|
15
|
+
default_task :start
|
|
16
|
+
|
|
17
|
+
register(Shoryuken::CLI::SQS, 'sqs', 'sqs COMMAND', 'SQS commands')
|
|
18
|
+
|
|
19
|
+
desc 'start', 'Start shoryuken'
|
|
20
|
+
method_option :concurrency, aliases: '-c', type: :numeric, desc: 'Processor threads to use'
|
|
21
|
+
method_option :daemon, aliases: '-d', type: :boolean, desc: 'Daemonize process'
|
|
22
|
+
method_option :queues, aliases: '-q', type: :array, desc: 'Queues to process with optional weights'
|
|
23
|
+
method_option :require, aliases: '-r', type: :string, desc: 'Dir or path of the workers'
|
|
24
|
+
method_option :config_file, aliases: '-C', type: :string, desc: 'Path to config file'
|
|
25
|
+
method_option :rails, aliases: '-R', type: :boolean, desc: 'Load Rails'
|
|
26
|
+
method_option :logfile, aliases: '-L', type: :string, desc: 'Path to logfile'
|
|
27
|
+
method_option :pidfile, aliases: '-P', type: :string, desc: 'Path to pidfile'
|
|
28
|
+
method_option :verbose, aliases: '-v', type: :boolean, desc: 'Print more verbose output'
|
|
29
|
+
def start
|
|
30
|
+
opts = options.to_h.symbolize_keys
|
|
31
|
+
|
|
32
|
+
# Keep compatibility with old CLI queue format
|
|
33
|
+
opts[:queues] = options.queues.map { |q| q.split(',') } if options.queues
|
|
34
|
+
|
|
35
|
+
if options.daemon && options.logfile.nil?
|
|
36
|
+
fail_task "You should set a logfile if you're going to daemonize"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Shoryuken::Runner.instance.run(opts.freeze)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
desc 'version', 'Print version'
|
|
43
|
+
def version
|
|
44
|
+
say "Shoryuken #{Shoryuken::VERSION}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
12
48
|
end
|
|
49
|
+
|
|
50
|
+
Shoryuken::CLI::Runner.start
|
data/examples/default_worker.rb
CHANGED
|
@@ -4,17 +4,6 @@ class DefaultWorker
|
|
|
4
4
|
shoryuken_options queue: 'default', auto_delete: true
|
|
5
5
|
|
|
6
6
|
def perform(sqs_msg, body)
|
|
7
|
-
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# multiple workers for the same queue
|
|
12
|
-
class DefaultWorker2
|
|
13
|
-
include Shoryuken::Worker
|
|
14
|
-
|
|
15
|
-
shoryuken_options queue: 'default', auto_delete: true
|
|
16
|
-
|
|
17
|
-
def perform(sqs_msg, body)
|
|
18
|
-
puts "DefaultWorker2: '#{body}'"
|
|
7
|
+
Shoryuken.logger.debug("Received message: '#{body}'")
|
|
19
8
|
end
|
|
20
9
|
end
|