shoryuken 5.1.1 → 6.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/.devcontainer/Dockerfile +17 -0
- data/.devcontainer/base.Dockerfile +43 -0
- data/.devcontainer/devcontainer.json +35 -0
- data/.github/workflows/specs.yml +10 -5
- data/.github/workflows/stale.yml +20 -0
- data/.gitignore +1 -1
- data/.rubocop.yml +1 -1
- data/Appraisals +8 -0
- data/CHANGELOG.md +57 -0
- data/Gemfile +1 -1
- data/README.md +8 -2
- data/Rakefile +14 -3
- data/bin/cli/sqs.rb +50 -5
- data/gemfiles/aws_sdk_core_2.gemfile +21 -0
- data/lib/shoryuken/environment_loader.rb +17 -3
- data/lib/shoryuken/extensions/active_job_adapter.rb +4 -2
- data/lib/shoryuken/launcher.rb +19 -0
- data/lib/shoryuken/manager.rb +40 -10
- data/lib/shoryuken/message.rb +11 -28
- data/lib/shoryuken/options.rb +1 -0
- data/lib/shoryuken/polling/strict_priority.rb +4 -2
- data/lib/shoryuken/polling/weighted_round_robin.rb +3 -5
- data/lib/shoryuken/runner.rb +4 -3
- data/lib/shoryuken/version.rb +1 -1
- data/lib/shoryuken.rb +4 -0
- data/spec/integration/launcher_spec.rb +29 -2
- data/spec/shoryuken/environment_loader_spec.rb +62 -9
- data/spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb +4 -0
- data/spec/shoryuken/extensions/active_job_wrapper_spec.rb +20 -0
- data/spec/shoryuken/launcher_spec.rb +60 -0
- data/spec/shoryuken/manager_spec.rb +37 -1
- data/spec/shoryuken/polling/weighted_round_robin_spec.rb +31 -6
- data/spec/shoryuken/queue_spec.rb +10 -5
- data/spec/shoryuken/worker/default_executor_spec.rb +48 -48
- data/spec/shoryuken_spec.rb +9 -0
- data/spec/spec_helper.rb +0 -4
- metadata +12 -4
- data/Gemfile.aws-sdk-core-v2 +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 47b6564c21a283ca5d0cd71f7f59b36b9c99776a541b2a51c61a9fd5b590be08
|
|
4
|
+
data.tar.gz: cf94b4ba4d9b296e0af112704cbe0ecd201f57726c284c790351f79a23680c7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d037b9887326e63ba1c8659a56e7707cf07b7a1a7d9f5027df7fb759d2896035335bc877487a346d7cac59e7b1916a8f5dc967e4431445b1e7ca9f6778282f7b
|
|
7
|
+
data.tar.gz: 4e0dd25a40a86a09ea87b0187d7f9f3d8525031b40830b47b29b434b688459e60209d7f8e4adb7d6c5deeedfb63b4139bceb0e38762b7fbf0dab884c1023063c
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# [Choice] Ruby version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.1, 3.0, 2, 2.7, 2.6, 3-bullseye, 3.1-bullseye, 3.0-bullseye, 2-bullseye, 2.7-bullseye, 2.6-bullseye, 3-buster, 3.1-buster, 3.0-buster, 2-buster, 2.7-buster, 2.6-buster
|
|
2
|
+
ARG VARIANT=2-bullseye
|
|
3
|
+
FROM mcr.microsoft.com/vscode/devcontainers/ruby:0-${VARIANT}
|
|
4
|
+
|
|
5
|
+
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
|
|
6
|
+
ARG NODE_VERSION="none"
|
|
7
|
+
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
|
8
|
+
|
|
9
|
+
# [Optional] Uncomment this section to install additional OS packages.
|
|
10
|
+
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
11
|
+
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
|
12
|
+
|
|
13
|
+
# [Optional] Uncomment this line to install additional gems.
|
|
14
|
+
# RUN gem install <your-gem-names-here>
|
|
15
|
+
|
|
16
|
+
# [Optional] Uncomment this line to install global node packages.
|
|
17
|
+
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# [Choice] Ruby version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.1, 3.0, 2, 2.7, 2.6, 3-bullseye, 3.1-bullseye, 3.0-bullseye, 2-bullseye, 2.7-bullseye, 2.6-bullseye, 3-buster, 3.1-buster, 3.0-buster, 2-buster, 2.7-buster, 2.6-buster
|
|
2
|
+
ARG VARIANT=2-bullseye
|
|
3
|
+
FROM ruby:${VARIANT}
|
|
4
|
+
|
|
5
|
+
# Copy library scripts to execute
|
|
6
|
+
COPY library-scripts/*.sh library-scripts/*.env /tmp/library-scripts/
|
|
7
|
+
|
|
8
|
+
# [Option] Install zsh
|
|
9
|
+
ARG INSTALL_ZSH="true"
|
|
10
|
+
# [Option] Upgrade OS packages to their latest versions
|
|
11
|
+
ARG UPGRADE_PACKAGES="true"
|
|
12
|
+
# Install needed packages and setup non-root user. Use a separate RUN statement to add your own dependencies.
|
|
13
|
+
ARG USERNAME=vscode
|
|
14
|
+
ARG USER_UID=1000
|
|
15
|
+
ARG USER_GID=$USER_UID
|
|
16
|
+
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
17
|
+
# Remove imagemagick due to https://security-tracker.debian.org/tracker/CVE-2019-10131
|
|
18
|
+
&& apt-get purge -y imagemagick imagemagick-6-common \
|
|
19
|
+
# Install common packages, non-root user, rvm, core build tools
|
|
20
|
+
&& bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \
|
|
21
|
+
&& bash /tmp/library-scripts/ruby-debian.sh "none" "${USERNAME}" "true" "true" \
|
|
22
|
+
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/*
|
|
23
|
+
|
|
24
|
+
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
|
|
25
|
+
ARG NODE_VERSION="none"
|
|
26
|
+
ENV NVM_DIR=/usr/local/share/nvm
|
|
27
|
+
ENV NVM_SYMLINK_CURRENT=true \
|
|
28
|
+
PATH=${NVM_DIR}/current/bin:${PATH}
|
|
29
|
+
RUN bash /tmp/library-scripts/node-debian.sh "${NVM_DIR}" "${NODE_VERSION}" "${USERNAME}" \
|
|
30
|
+
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*
|
|
31
|
+
|
|
32
|
+
# Remove library scripts for final image
|
|
33
|
+
RUN rm -rf /tmp/library-scripts
|
|
34
|
+
|
|
35
|
+
# [Optional] Uncomment this section to install additional OS packages.
|
|
36
|
+
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
37
|
+
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
|
38
|
+
|
|
39
|
+
# [Optional] Uncomment this line to install additional gems.
|
|
40
|
+
# RUN gem install <your-gem-names-here>
|
|
41
|
+
|
|
42
|
+
# [Optional] Uncomment this line to install global node packages.
|
|
43
|
+
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
|
2
|
+
// https://github.com/microsoft/vscode-dev-containers/tree/v0.224.3/containers/ruby
|
|
3
|
+
{
|
|
4
|
+
"name": "Ruby",
|
|
5
|
+
"build": {
|
|
6
|
+
"dockerfile": "Dockerfile",
|
|
7
|
+
"args": {
|
|
8
|
+
// Update 'VARIANT' to pick a Ruby version: 3, 3.1, 3.0, 2, 2.7, 2.6
|
|
9
|
+
// Append -bullseye or -buster to pin to an OS version.
|
|
10
|
+
// Use -bullseye variants on local on arm64/Apple Silicon.
|
|
11
|
+
"VARIANT": "3-bullseye",
|
|
12
|
+
// Options
|
|
13
|
+
"NODE_VERSION": "none"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// Set *default* container specific settings.json values on container create.
|
|
18
|
+
"settings": {},
|
|
19
|
+
|
|
20
|
+
// Add the IDs of extensions you want installed when the container is created.
|
|
21
|
+
"extensions": ["rebornix.Ruby"],
|
|
22
|
+
|
|
23
|
+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
24
|
+
// "forwardPorts": [],
|
|
25
|
+
|
|
26
|
+
// Use 'postCreateCommand' to run commands after the container is created.
|
|
27
|
+
// "postCreateCommand": "ruby --version",
|
|
28
|
+
|
|
29
|
+
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
|
30
|
+
"remoteUser": "vscode",
|
|
31
|
+
"features": {
|
|
32
|
+
"github-cli": "latest",
|
|
33
|
+
"aws-cli": "latest"
|
|
34
|
+
}
|
|
35
|
+
}
|
data/.github/workflows/specs.yml
CHANGED
|
@@ -9,9 +9,14 @@ jobs:
|
|
|
9
9
|
name: All Specs
|
|
10
10
|
strategy:
|
|
11
11
|
matrix:
|
|
12
|
-
ruby: ['2.4
|
|
13
|
-
gemfile: ['Gemfile', '
|
|
12
|
+
ruby: ['2.4', '2.5', '2.6', '2.7', '3.0']
|
|
13
|
+
gemfile: ['Gemfile', 'gemfiles/aws_sdk_core_2.gemfile']
|
|
14
14
|
runs-on: ubuntu-20.04
|
|
15
|
+
services:
|
|
16
|
+
moto_sqs:
|
|
17
|
+
image: quay.io/cjlarose/moto-sqs-server:1.1.0
|
|
18
|
+
ports:
|
|
19
|
+
- 5000:5000
|
|
15
20
|
env:
|
|
16
21
|
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
|
17
22
|
steps:
|
|
@@ -22,9 +27,9 @@ jobs:
|
|
|
22
27
|
ruby-version: ${{ matrix.ruby }}
|
|
23
28
|
bundler-cache: true
|
|
24
29
|
- name: Run specs
|
|
25
|
-
env:
|
|
26
|
-
SPEC_ALL: true
|
|
27
30
|
run: bundle exec rake spec
|
|
31
|
+
- name: Run integration specs
|
|
32
|
+
run: bundle exec rake spec:integration
|
|
28
33
|
rails_specs:
|
|
29
34
|
name: Rails Specs
|
|
30
35
|
strategy:
|
|
@@ -54,4 +59,4 @@ jobs:
|
|
|
54
59
|
ruby-version: ${{ matrix.ruby }}
|
|
55
60
|
bundler-cache: true
|
|
56
61
|
- name: Run Rails specs
|
|
57
|
-
run: bundle exec rake
|
|
62
|
+
run: bundle exec rake spec:rails
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: "Close stale issues and PRs"
|
|
2
|
+
on:
|
|
3
|
+
schedule:
|
|
4
|
+
- cron: "30 1 * * *" # At 01:30 - https://crontab.guru/#30_1_*_*_*
|
|
5
|
+
workflow_dispatch: {}
|
|
6
|
+
jobs:
|
|
7
|
+
stale:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
permissions:
|
|
10
|
+
issues: write
|
|
11
|
+
pull-requests: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/stale@v4
|
|
14
|
+
with:
|
|
15
|
+
stale-issue-message: This issue is now marked as stale because it hasn't seen activity for a while. Add a comment or it will be closed soon.
|
|
16
|
+
stale-pr-message: This PR is now marked as stale because it hasn't seen activity for a while. Add a comment or it will be closed soon.
|
|
17
|
+
close-issue-message: This issue was closed because it hasn't seen activity for a while.
|
|
18
|
+
close-pr-message: This PR was closed because it hasn't seen activity for a while.
|
|
19
|
+
days-before-stale: 60
|
|
20
|
+
days-before-close: 7
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,60 @@
|
|
|
1
|
+
## [v6.0.0] - 2022-02-18
|
|
2
|
+
|
|
3
|
+
- Breaking changes: Initialize Rails before parsing config file
|
|
4
|
+
- [#686](https://github.com/ruby-shoryuken/shoryuken/pull/686)
|
|
5
|
+
- Previously, Shoryuken read its configuration from an optional YAML file, then allowed CLI arguments to override those, then initialized the Rails application (provided that `--rails` or `-R` was specified). This behavior meant that the config file did not have access to things like environment variables that were initialized by Rails (such as when using `dotenv`). With this change, Rails is initialized much earlier in the process. After Rails is initialized, the YAML configuration file is interpreted, and CLI arguments are finally interpreted last. Most applications will not need to undergo changes in order to upgrade, but the new load order could technically result in different behavior depending on the application's YAML configuration file or Rails initializers.
|
|
6
|
+
|
|
7
|
+
## [v5.3.2] - 2022-01-19
|
|
8
|
+
|
|
9
|
+
- (Bugfix) Preserve queue weights when unpausing queues
|
|
10
|
+
- [#687](https://github.com/ruby-shoryuken/shoryuken/pull/687)
|
|
11
|
+
|
|
12
|
+
- Improve error message on startup when shoryuken has insufficient permissions to access a queue
|
|
13
|
+
- [#691](https://github.com/ruby-shoryuken/shoryuken/pull/691)
|
|
14
|
+
|
|
15
|
+
## [v5.3.1] - 2022-01-07
|
|
16
|
+
|
|
17
|
+
- (Bugfix) Fix issue where, when using the TSTP or USR1 signals for soft shutdowns, it was possible for shoryuken to terminate without first attempting to handle all messages it fetched from SQS
|
|
18
|
+
- [#676](https://github.com/ruby-shoryuken/shoryuken/pull/676)
|
|
19
|
+
|
|
20
|
+
## [v5.3.0] - 2021-10-31
|
|
21
|
+
|
|
22
|
+
- (Refactor) Use Forwardable within Message to avoid method boilerplate
|
|
23
|
+
- [#681](https://github.com/ruby-shoryuken/shoryuken/pull/681)
|
|
24
|
+
|
|
25
|
+
- Add basic health check API
|
|
26
|
+
- [#679](https://github.com/ruby-shoryuken/shoryuken/pull/679)
|
|
27
|
+
|
|
28
|
+
## [v5.2.3] - 2021-07-29
|
|
29
|
+
|
|
30
|
+
- Fire new `:utilization_update` event any time a worker pool's utilization changes
|
|
31
|
+
- [#673](https://github.com/ruby-shoryuken/shoryuken/pull/673)
|
|
32
|
+
|
|
33
|
+
## [v5.2.2] - 2021-06-22
|
|
34
|
+
|
|
35
|
+
- When using ActiveJob queue name prefixing, avoid applying prefix to queues configured with a URL or ARN
|
|
36
|
+
- [#667](https://github.com/ruby-shoryuken/shoryuken/pull/667)
|
|
37
|
+
|
|
38
|
+
## [v5.2.1] - 2021-04-06
|
|
39
|
+
|
|
40
|
+
- Reduce message batch sizes in `shoryuken sqs requeue` and `shoryuken sqs mv` commands
|
|
41
|
+
- [#666](https://github.com/ruby-shoryuken/shoryuken/pull/666)
|
|
42
|
+
|
|
43
|
+
- Fix bug in `shoryuken sqs requeue` and `shoryuken sqs mv` where those commands would exceed the SQS `SendMessageBatch` maximum payload size
|
|
44
|
+
- [#663](https://github.com/ruby-shoryuken/shoryuken/issues/663)
|
|
45
|
+
- [#664](https://github.com/ruby-shoryuken/shoryuken/pull/664)
|
|
46
|
+
|
|
47
|
+
- Remove test stub for `Concurrent.global_io_executor`
|
|
48
|
+
- [#662](https://github.com/ruby-shoryuken/shoryuken/pull/662)
|
|
49
|
+
|
|
50
|
+
- Run integration tests on CI
|
|
51
|
+
- [#660](https://github.com/ruby-shoryuken/shoryuken/pull/660)
|
|
52
|
+
|
|
53
|
+
## [v5.2.0] - 2021-02-26
|
|
54
|
+
|
|
55
|
+
- Set `executions` correctly for ActiveJob jobs
|
|
56
|
+
- [#657](https://github.com/phstc/shoryuken/pull/657)
|
|
57
|
+
|
|
1
58
|
## [v5.1.1] - 2021-02-10
|
|
2
59
|
|
|
3
60
|
- Fix regression in Ruby 3.0 introduced in Shoryuken 5.1.0, where enqueueing jobs with ActiveJob to workers that used keyword arguments would fail
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -69,7 +69,7 @@ For more information check the [wiki page](https://github.com/phstc/shoryuken/wi
|
|
|
69
69
|
|
|
70
70
|
### Testing
|
|
71
71
|
|
|
72
|
-
To run all specs against the latest dependency vesions, execute
|
|
72
|
+
To run all unit specs against the latest dependency vesions, execute
|
|
73
73
|
|
|
74
74
|
```sh
|
|
75
75
|
bundle exec rake spec
|
|
@@ -78,5 +78,11 @@ bundle exec rake spec
|
|
|
78
78
|
To run all Rails-related specs against all supported versions of Rails, execute
|
|
79
79
|
|
|
80
80
|
```sh
|
|
81
|
-
bundle exec appraisal rake
|
|
81
|
+
bundle exec appraisal rake spec:rails
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
To run integration specs, start a mock SQS server on `localhost:5000`. One such option is [cjlarose/moto-sqs-server](https://github.com/cjlarose/moto-sqs-server). Then execute
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
bundle exec rake spec:integration
|
|
82
88
|
```
|
data/Rakefile
CHANGED
|
@@ -3,10 +3,21 @@ $stdout.sync = true
|
|
|
3
3
|
|
|
4
4
|
begin
|
|
5
5
|
require 'rspec/core/rake_task'
|
|
6
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
|
7
|
+
t.exclude_pattern = 'spec/integration/**/*_spec.rb'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
namespace :spec do
|
|
11
|
+
desc 'Run Rails specs only'
|
|
12
|
+
RSpec::Core::RakeTask.new(:rails) do |t|
|
|
13
|
+
t.pattern = 'spec/shoryuken/{environment_loader_spec,extensions/active_job_*}.rb'
|
|
14
|
+
end
|
|
7
15
|
|
|
8
|
-
|
|
9
|
-
|
|
16
|
+
desc 'Run integration specs only'
|
|
17
|
+
RSpec::Core::RakeTask.new(:integration) do |t|
|
|
18
|
+
t.pattern = 'spec/integration/**/*_spec.rb'
|
|
19
|
+
end
|
|
20
|
+
end
|
|
10
21
|
rescue LoadError
|
|
11
22
|
end
|
|
12
23
|
|
data/bin/cli/sqs.rb
CHANGED
|
@@ -4,6 +4,9 @@ require 'date'
|
|
|
4
4
|
module Shoryuken
|
|
5
5
|
module CLI
|
|
6
6
|
class SQS < Base
|
|
7
|
+
# See https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/quotas-messages.html
|
|
8
|
+
MAX_BATCH_SIZE = 256 * 1024
|
|
9
|
+
|
|
7
10
|
namespace :sqs
|
|
8
11
|
class_option :endpoint, aliases: '-e', type: :string, default: ENV['SHORYUKEN_SQS_ENDPOINT'], desc: 'Endpoint URL'
|
|
9
12
|
|
|
@@ -51,14 +54,56 @@ module Shoryuken
|
|
|
51
54
|
end
|
|
52
55
|
end
|
|
53
56
|
|
|
54
|
-
def batch_send(url, messages,
|
|
55
|
-
messages.to_a.flatten.map(&method(:normalize_dump_message))
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
def batch_send(url, messages, max_batch_size = 10)
|
|
58
|
+
messages = messages.to_a.flatten.map(&method(:normalize_dump_message))
|
|
59
|
+
batch_send_normalized_messages url, messages, max_batch_size
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def batch_send_normalized_messages(url, messages, max_batch_size)
|
|
63
|
+
# Repeatedly take the longest prefix of messages such that
|
|
64
|
+
# 1. The number of messages is less than or equal to max_batch_size
|
|
65
|
+
# 2. The total message payload size is less than or equal to the
|
|
66
|
+
# batch payload limit
|
|
67
|
+
while messages.size.positive?
|
|
68
|
+
batch_size = max_batch_size
|
|
69
|
+
loop do
|
|
70
|
+
batch = messages.take batch_size
|
|
71
|
+
|
|
72
|
+
unless batch.size == 1 || batch_payload_size(batch) <= MAX_BATCH_SIZE
|
|
73
|
+
batch_size = batch.size - 1
|
|
74
|
+
next
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
sqs.send_message_batch(queue_url: url, entries: batch).failed.any? do |failure|
|
|
78
|
+
say "Could not requeue #{failure.id}, code: #{failure.code}", :yellow
|
|
79
|
+
end
|
|
80
|
+
messages = messages.drop batch.size
|
|
81
|
+
break
|
|
58
82
|
end
|
|
59
83
|
end
|
|
60
84
|
end
|
|
61
85
|
|
|
86
|
+
def batch_payload_size(messages)
|
|
87
|
+
messages.sum(&method(:message_size))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def message_size(message)
|
|
91
|
+
attribute_size = (message[:message_attributes] || []).sum do |name, value|
|
|
92
|
+
name_size = name.to_s.bytesize
|
|
93
|
+
data_type_size = value[:data_type].bytesize
|
|
94
|
+
value_size = if value[:string_value]
|
|
95
|
+
value[:string_value].bytesize
|
|
96
|
+
elsif value[:binary_value]
|
|
97
|
+
value[:binary_value].bytesize
|
|
98
|
+
end
|
|
99
|
+
name_size + data_type_size + value_size
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
body_size = message[:message_body].bytesize
|
|
103
|
+
|
|
104
|
+
attribute_size + body_size
|
|
105
|
+
end
|
|
106
|
+
|
|
62
107
|
def find_all(url, limit)
|
|
63
108
|
count = 0
|
|
64
109
|
batch_size = limit > 10 ? 10 : limit
|
|
@@ -160,7 +205,7 @@ module Shoryuken
|
|
|
160
205
|
end
|
|
161
206
|
|
|
162
207
|
desc 'requeue QUEUE-NAME PATH', 'Requeues messages from a dump file'
|
|
163
|
-
method_option :batch_size, aliases: '-n', type: :numeric, default: 10, desc: 'number of messages per batch to send'
|
|
208
|
+
method_option :batch_size, aliases: '-n', type: :numeric, default: 10, desc: 'maximum number of messages per batch to send'
|
|
164
209
|
def requeue(queue_name, path)
|
|
165
210
|
fail_task "Path #{path} not found" unless File.exist?(path)
|
|
166
211
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
group :test do
|
|
6
|
+
gem "activejob"
|
|
7
|
+
gem "aws-sdk-core", "~> 2"
|
|
8
|
+
gem "codeclimate-test-reporter", require: nil
|
|
9
|
+
gem "httparty"
|
|
10
|
+
gem "multi_xml"
|
|
11
|
+
gem "simplecov"
|
|
12
|
+
gem "webrick"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
group :development do
|
|
16
|
+
gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
|
|
17
|
+
gem "pry-byebug", "3.9.0"
|
|
18
|
+
gem "rubocop"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
gemspec path: "../"
|
|
@@ -18,12 +18,12 @@ module Shoryuken
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def setup_options
|
|
21
|
+
initialize_rails if load_rails?
|
|
21
22
|
initialize_options
|
|
22
23
|
initialize_logger
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
def load
|
|
26
|
-
load_rails if Shoryuken.options[:rails]
|
|
27
27
|
prefix_active_job_queue_names
|
|
28
28
|
parse_queues
|
|
29
29
|
require_workers
|
|
@@ -55,7 +55,7 @@ module Shoryuken
|
|
|
55
55
|
Shoryuken.logger.level = Logger::DEBUG if Shoryuken.options[:verbose]
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
def
|
|
58
|
+
def initialize_rails
|
|
59
59
|
# Adapted from: https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/cli.rb
|
|
60
60
|
|
|
61
61
|
require 'rails'
|
|
@@ -79,7 +79,13 @@ module Shoryuken
|
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
+
def load_rails?
|
|
83
|
+
options[:rails]
|
|
84
|
+
end
|
|
85
|
+
|
|
82
86
|
def prefix_active_job_queue_name(queue_name, weight)
|
|
87
|
+
return [queue_name, weight] if queue_name.start_with?('https://', 'arn:')
|
|
88
|
+
|
|
83
89
|
queue_name_prefix = ::ActiveJob::Base.queue_name_prefix
|
|
84
90
|
queue_name_delimiter = ::ActiveJob::Base.queue_name_delimiter
|
|
85
91
|
|
|
@@ -157,9 +163,17 @@ module Shoryuken
|
|
|
157
163
|
|
|
158
164
|
return if non_existent_queues.none?
|
|
159
165
|
|
|
166
|
+
# NOTE: HEREDOC's ~ operator removes indents, but is only available Ruby 2.3+
|
|
167
|
+
# See github PR: https://github.com/ruby-shoryuken/shoryuken/pull/691#issuecomment-1007653595
|
|
168
|
+
error_msg = <<-MSG.gsub(/^\s+/, '')
|
|
169
|
+
The specified queue(s) #{non_existent_queues.join(', ')} do not exist.
|
|
170
|
+
Try 'shoryuken sqs create QUEUE-NAME' for creating a queue with default settings.
|
|
171
|
+
It's also possible that you don't have permission to access the specified queues.
|
|
172
|
+
MSG
|
|
173
|
+
|
|
160
174
|
fail(
|
|
161
175
|
ArgumentError,
|
|
162
|
-
|
|
176
|
+
error_msg
|
|
163
177
|
)
|
|
164
178
|
end
|
|
165
179
|
|
|
@@ -82,8 +82,10 @@ module ActiveJob
|
|
|
82
82
|
|
|
83
83
|
shoryuken_options body_parser: :json, auto_delete: true
|
|
84
84
|
|
|
85
|
-
def perform(
|
|
86
|
-
|
|
85
|
+
def perform(sqs_msg, hash)
|
|
86
|
+
receive_count = sqs_msg.attributes['ApproximateReceiveCount'].to_i
|
|
87
|
+
past_receives = receive_count - 1
|
|
88
|
+
Base.execute hash.merge({ 'executions' => past_receives })
|
|
87
89
|
end
|
|
88
90
|
end
|
|
89
91
|
|
data/lib/shoryuken/launcher.rb
CHANGED
|
@@ -28,12 +28,30 @@ module Shoryuken
|
|
|
28
28
|
|
|
29
29
|
initiate_stop
|
|
30
30
|
|
|
31
|
+
stop_new_dispatching
|
|
32
|
+
await_dispatching_in_progress
|
|
33
|
+
|
|
31
34
|
executor.shutdown
|
|
32
35
|
executor.wait_for_termination
|
|
33
36
|
end
|
|
34
37
|
|
|
38
|
+
def healthy?
|
|
39
|
+
Shoryuken.groups.keys.all? do |group|
|
|
40
|
+
manager = @managers.find { |m| m.group == group }
|
|
41
|
+
manager && manager.running?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
35
45
|
private
|
|
36
46
|
|
|
47
|
+
def stop_new_dispatching
|
|
48
|
+
@managers.each(&:stop_new_dispatching)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def await_dispatching_in_progress
|
|
52
|
+
@managers.each(&:await_dispatching_in_progress)
|
|
53
|
+
end
|
|
54
|
+
|
|
37
55
|
def executor
|
|
38
56
|
@_executor ||= Shoryuken.launcher_executor || Concurrent.global_io_executor
|
|
39
57
|
end
|
|
@@ -71,6 +89,7 @@ module Shoryuken
|
|
|
71
89
|
def create_managers
|
|
72
90
|
Shoryuken.groups.map do |group, options|
|
|
73
91
|
Shoryuken::Manager.new(
|
|
92
|
+
group,
|
|
74
93
|
Shoryuken::Fetcher.new(group),
|
|
75
94
|
Shoryuken.polling_strategy(group).new(options[:queues], Shoryuken.delay(group)),
|
|
76
95
|
options[:concurrency],
|
data/lib/shoryuken/manager.rb
CHANGED
|
@@ -6,27 +6,47 @@ module Shoryuken
|
|
|
6
6
|
# See https://github.com/phstc/shoryuken/issues/348#issuecomment-292847028
|
|
7
7
|
MIN_DISPATCH_INTERVAL = 0.1
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@
|
|
13
|
-
@
|
|
14
|
-
@
|
|
15
|
-
@
|
|
9
|
+
attr_reader :group
|
|
10
|
+
|
|
11
|
+
def initialize(group, fetcher, polling_strategy, concurrency, executor)
|
|
12
|
+
@group = group
|
|
13
|
+
@fetcher = fetcher
|
|
14
|
+
@polling_strategy = polling_strategy
|
|
15
|
+
@max_processors = concurrency
|
|
16
|
+
@busy_processors = Concurrent::AtomicFixnum.new(0)
|
|
17
|
+
@executor = executor
|
|
18
|
+
@running = Concurrent::AtomicBoolean.new(true)
|
|
19
|
+
@stop_new_dispatching = Concurrent::AtomicBoolean.new(false)
|
|
20
|
+
@dispatching_release_signal = ::Queue.new
|
|
16
21
|
end
|
|
17
22
|
|
|
18
23
|
def start
|
|
24
|
+
fire_utilization_update_event
|
|
19
25
|
dispatch_loop
|
|
20
26
|
end
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
def stop_new_dispatching
|
|
29
|
+
@stop_new_dispatching.make_true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def await_dispatching_in_progress
|
|
33
|
+
# There might still be a dispatching on-going, as the response from SQS could take some time
|
|
34
|
+
# We don't want to stop the process before processing incoming messages, as they would stay "in-flight" for some time on SQS
|
|
35
|
+
# We use a queue, as the dispatch_loop is running on another thread, and this is a efficient way of communicating between threads.
|
|
36
|
+
@dispatching_release_signal.pop
|
|
37
|
+
end
|
|
23
38
|
|
|
24
39
|
def running?
|
|
25
40
|
@running.true? && @executor.running?
|
|
26
41
|
end
|
|
27
42
|
|
|
43
|
+
private
|
|
44
|
+
|
|
28
45
|
def dispatch_loop
|
|
29
|
-
|
|
46
|
+
if @stop_new_dispatching.true? || !running?
|
|
47
|
+
@dispatching_release_signal << 1
|
|
48
|
+
return
|
|
49
|
+
end
|
|
30
50
|
|
|
31
51
|
@executor.post { dispatch }
|
|
32
52
|
end
|
|
@@ -59,6 +79,8 @@ module Shoryuken
|
|
|
59
79
|
|
|
60
80
|
def processor_done(queue)
|
|
61
81
|
@busy_processors.decrement
|
|
82
|
+
fire_utilization_update_event
|
|
83
|
+
|
|
62
84
|
client_queue = Shoryuken::Client.queues(queue)
|
|
63
85
|
return unless client_queue.fifo?
|
|
64
86
|
return unless @polling_strategy.respond_to?(:message_processed)
|
|
@@ -72,6 +94,7 @@ module Shoryuken
|
|
|
72
94
|
logger.debug { "Assigning #{sqs_msg.message_id}" }
|
|
73
95
|
|
|
74
96
|
@busy_processors.increment
|
|
97
|
+
fire_utilization_update_event
|
|
75
98
|
|
|
76
99
|
Concurrent::Promise
|
|
77
100
|
.execute(executor: @executor) { Processor.process(queue_name, sqs_msg) }
|
|
@@ -87,7 +110,6 @@ module Shoryuken
|
|
|
87
110
|
|
|
88
111
|
def dispatch_single_messages(queue)
|
|
89
112
|
messages = @fetcher.fetch(queue, ready)
|
|
90
|
-
|
|
91
113
|
@polling_strategy.messages_found(queue.name, messages.size)
|
|
92
114
|
messages.each { |message| assign(queue.name, message) }
|
|
93
115
|
end
|
|
@@ -114,5 +136,13 @@ module Shoryuken
|
|
|
114
136
|
|
|
115
137
|
@running.make_false
|
|
116
138
|
end
|
|
139
|
+
|
|
140
|
+
def fire_utilization_update_event
|
|
141
|
+
fire_event :utilization_update, false, {
|
|
142
|
+
group: @group,
|
|
143
|
+
max_processors: @max_processors,
|
|
144
|
+
busy_processors: busy
|
|
145
|
+
}
|
|
146
|
+
end
|
|
117
147
|
end
|
|
118
148
|
end
|
data/lib/shoryuken/message.rb
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
module Shoryuken
|
|
2
2
|
class Message
|
|
3
|
+
extend Forwardable
|
|
4
|
+
|
|
5
|
+
def_delegators(:data,
|
|
6
|
+
:message_id,
|
|
7
|
+
:receipt_handle,
|
|
8
|
+
:md5_of_body,
|
|
9
|
+
:body,
|
|
10
|
+
:attributes,
|
|
11
|
+
:md5_of_message_attributes,
|
|
12
|
+
:message_attributes)
|
|
13
|
+
|
|
3
14
|
attr_accessor :client, :queue_url, :queue_name, :data
|
|
4
15
|
|
|
5
16
|
def initialize(client, queue, data)
|
|
@@ -29,33 +40,5 @@ module Shoryuken
|
|
|
29
40
|
visibility_timeout: timeout
|
|
30
41
|
)
|
|
31
42
|
end
|
|
32
|
-
|
|
33
|
-
def message_id
|
|
34
|
-
data.message_id
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def receipt_handle
|
|
38
|
-
data.receipt_handle
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def md5_of_body
|
|
42
|
-
data.md5_of_body
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def body
|
|
46
|
-
data.body
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def attributes
|
|
50
|
-
data.attributes
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def md5_of_message_attributes
|
|
54
|
-
data.md5_of_message_attributes
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def message_attributes
|
|
58
|
-
data.message_attributes
|
|
59
|
-
end
|
|
60
43
|
end
|
|
61
44
|
end
|