shoryuken 5.3.2 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1002845b2232c5f7491b2839d7851be5afdb79a3a11e73e2249b81e1f2ea4ec4
4
- data.tar.gz: 8398fa557fba47360763bb83ea4e0f529b2c69bad8b15fb3163e03c517b460d8
3
+ metadata.gz: ba3ab903a9490d367ced7d0d70cb3f3aae142abc17dc466f2248b64ee5566773
4
+ data.tar.gz: e3f84b09a3e3a888ba280ade138fc8b9c902a0d39d27188ac6e6576a19a6e482
5
5
  SHA512:
6
- metadata.gz: 010d2f45fe45e6967435b57c1f0c7601f9d3a43a8c1108edbf97b303e60e108e0c6be1ba28915a43bc84f5904bd7f3d634916251b8b1c0d83143d75bdccaaca7
7
- data.tar.gz: 00c8f19de3a9fd241bb236023479bd5c3bd27f731001f036377c05b75c18bce119b08666eb13649606904e2950f937f52615eba84facb44074099fde1fc97534
6
+ metadata.gz: 7273ea2e72c35dd4c443d3376da6e787e0c3c86ee4a048700a73391e662c631e0509bd22bf7cf7016d2bfe9cf35273706037b3621fc4cd5c6c2b19c7a39bb727
7
+ data.tar.gz: d08532edb206f643cf3fec6ff197efc84768871f90a7ef185ebc1030f5027b8dd333642036a601e8884225a750cd4666bfbc349cb7f2a576a0f2e8fc9d0ece48
@@ -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
+ }
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -9,7 +9,7 @@ jobs:
9
9
  name: All Specs
10
10
  strategy:
11
11
  matrix:
12
- ruby: ['2.4', '2.5', '2.6', '2.7', '3.0']
12
+ ruby: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2']
13
13
  gemfile: ['Gemfile', 'gemfiles/aws_sdk_core_2.gemfile']
14
14
  runs-on: ubuntu-20.04
15
15
  services:
@@ -34,7 +34,7 @@ jobs:
34
34
  name: Rails Specs
35
35
  strategy:
36
36
  matrix:
37
- rails: ['4.2', '5.2', '6.0', '6.1']
37
+ rails: ['4.2', '5.2', '6.0', '6.1', '7.0']
38
38
  include:
39
39
  - rails: '4.2'
40
40
  ruby: '2.2'
@@ -48,6 +48,9 @@ jobs:
48
48
  - rails: '6.1'
49
49
  ruby: '3.0'
50
50
  gemfile: gemfiles/rails_6_1.gemfile
51
+ - rails: '7.0'
52
+ ruby: '3.1'
53
+ gemfile: gemfiles/rails_7_0.gemfile
51
54
  runs-on: ubuntu-20.04
52
55
  env:
53
56
  BUNDLE_GEMFILE: ${{ matrix.gemfile }}
@@ -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@v8
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/Appraisals CHANGED
@@ -34,3 +34,9 @@ appraise 'rails_6_1' do
34
34
  gem 'activejob', '~> 6.1'
35
35
  end
36
36
  end
37
+
38
+ appraise 'rails_7_0' do
39
+ group :test do
40
+ gem 'activejob', '~> 7.0'
41
+ end
42
+ end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## [v6.1.0] - 2023-11-01
2
+
3
+ - Add GitHub Codespaces
4
+ - [#698](https://github.com/ruby-shoryuken/shoryuken/pull/698)
5
+
6
+ - Fix spec for ruby 3.0
7
+ - [#727](https://github.com/ruby-shoryuken/shoryuken/pull/727)
8
+
9
+ - Upgrade test matrix. Add Ruby 3.1, Ruby 3.2 and Rails 7
10
+ - [#739](https://github.com/ruby-shoryuken/shoryuken/pull/739)
11
+
12
+ - Fire stopped event after executor is stopped
13
+ - [#741](https://github.com/ruby-shoryuken/shoryuken/pull/741)
14
+
15
+ - Allow setup custom exception handlers for failing jobs
16
+ - [#742](https://github.com/ruby-shoryuken/shoryuken/pull/742)
17
+
18
+ - Configure dependabot to update GH Actions
19
+ - [#745](https://github.com/ruby-shoryuken/shoryuken/pull/745)
20
+
21
+ - Stop the dispatching of new messages when a SIGTERM signal has been received
22
+ - [#750](https://github.com/ruby-shoryuken/shoryuken/pull/750)
23
+
24
+ ## [v6.0.0] - 2022-02-18
25
+
26
+ - Breaking changes: Initialize Rails before parsing config file
27
+ - [#686](https://github.com/ruby-shoryuken/shoryuken/pull/686)
28
+ - 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.
29
+
1
30
  ## [v5.3.2] - 2022-01-19
2
31
 
3
32
  - (Bugfix) Preserve queue weights when unpausing queues
data/Gemfile CHANGED
@@ -15,6 +15,6 @@ end
15
15
 
16
16
  group :development do
17
17
  gem 'appraisal', git: 'https://github.com/thoughtbot/appraisal.git'
18
- gem 'pry-byebug', '3.9.0'
18
+ gem 'pry-byebug'
19
19
  gem 'rubocop', '<= 1.12'
20
20
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- **I'm looking for Shoryuken maintainers, are you interested on helping to maintain Shoryuken? Fill up this form https://forms.gle/8kTso8ixa9Sfp6rJ9**
1
+ **I'm looking for Shoryuken maintainers, are you interested on helping to maintain Shoryuken? [Join our Slack](https://join.slack.com/t/shoryuken/shared_invite/zt-19xjq3iqc-KmoJ6eU6~qvZNqcLzIrjww)**
2
2
 
3
3
  # Shoryuken
4
4
 
@@ -86,3 +86,21 @@ To run integration specs, start a mock SQS server on `localhost:5000`. One such
86
86
  ```sh
87
87
  bundle exec rake spec:integration
88
88
  ```
89
+
90
+ ### To release a new version
91
+
92
+ Compare latest tag with HEAD:
93
+
94
+ ```sh
95
+ git log $(git describe --tags --abbrev=0)..HEAD --oneline
96
+ ```
97
+
98
+ then update CHANGELOG.md.
99
+
100
+ Update version in `lib/shoryuken/version.rb` with the appropriate version number [SEMVER](https://semver.org/).
101
+
102
+ then run:
103
+
104
+ ```sh
105
+ bundle exec rake release
106
+ ```
@@ -14,7 +14,7 @@ end
14
14
 
15
15
  group :development do
16
16
  gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
17
- gem "pry-byebug", "3.9.0"
17
+ gem "pry-byebug"
18
18
  gem "rubocop"
19
19
  end
20
20
 
@@ -0,0 +1,22 @@
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 "aws-sdk-core", "~> 3"
8
+ gem "aws-sdk-sqs"
9
+ gem "codeclimate-test-reporter", require: nil
10
+ gem "httparty"
11
+ gem "multi_xml"
12
+ gem "simplecov"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
17
+ gem "rubocop"
18
+ gem "pry", ">= 0.14.2"
19
+ gem "pry-byebug", ">= 3.10.1"
20
+ end
21
+
22
+ gemspec path: "../"
@@ -0,0 +1,10 @@
1
+ module Shoryuken
2
+ class DefaultExceptionHandler
3
+ extend Util
4
+
5
+ def self.call(exception, _queue, _sqs_msg)
6
+ logger.error { "Processor failed: #{exception.message}" }
7
+ logger.error { exception.backtrace.join("\n") } if exception.backtrace
8
+ end
9
+ end
10
+ end
@@ -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 load_rails
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,6 +79,10 @@ 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)
83
87
  return [queue_name, weight] if queue_name.start_with?('https://', 'arn:')
84
88
 
@@ -66,8 +66,11 @@ module ActiveJob
66
66
  }
67
67
 
68
68
  if queue.fifo?
69
- # See https://github.com/phstc/shoryuken/issues/457
70
- msg[:message_deduplication_id] = Digest::SHA256.hexdigest(JSON.dump(body.except('job_id')))
69
+ # See https://github.com/ruby-shoryuken/shoryuken/issues/457 and
70
+ # https://github.com/ruby-shoryuken/shoryuken/pull/750#issuecomment-1781317929
71
+ msg[:message_deduplication_id] = Digest::SHA256.hexdigest(
72
+ JSON.dump(body.except('job_id', 'enqueued_at'))
73
+ )
71
74
  end
72
75
 
73
76
  msg.merge(job_params.except(:message_attributes))
@@ -11,7 +11,7 @@ module Shoryuken
11
11
  end
12
12
  end
13
13
 
14
- # Initializes SQS SendMessage parameters on instances of ActiveJobe::Base
14
+ # Initializes SQS SendMessage parameters on instances of ActiveJob::Base
15
15
  # to the empty hash, and populates it whenever `#enqueue` is called, such
16
16
  # as when using ActiveJob::Base.set.
17
17
  module SQSSendMessageParametersSupport
@@ -16,11 +16,13 @@ module Shoryuken
16
16
  def stop!
17
17
  initiate_stop
18
18
 
19
- executor.shutdown
19
+ # Don't await here so the timeout below is not delayed
20
+ stop_new_dispatching
20
21
 
21
- return if executor.wait_for_termination(Shoryuken.options[:timeout])
22
+ executor.shutdown
23
+ executor.kill unless executor.wait_for_termination(Shoryuken.options[:timeout])
22
24
 
23
- executor.kill
25
+ fire_event(:stopped)
24
26
  end
25
27
 
26
28
  def stop
@@ -33,6 +35,8 @@ module Shoryuken
33
35
 
34
36
  executor.shutdown
35
37
  executor.wait_for_termination
38
+
39
+ fire_event(:stopped)
36
40
  end
37
41
 
38
42
  def healthy?
@@ -30,11 +30,11 @@ module Shoryuken
30
30
  end
31
31
 
32
32
  def self.logger
33
- @logger || initialize_logger
33
+ @logger ||= initialize_logger
34
34
  end
35
35
 
36
36
  def self.logger=(log)
37
- @logger = (log ? log : Logger.new('/dev/null'))
37
+ @logger = (log || Logger.new('/dev/null'))
38
38
  end
39
39
  end
40
40
  end
@@ -11,19 +11,21 @@ module Shoryuken
11
11
  dispatch: [],
12
12
  utilization_update: [],
13
13
  quiet: [],
14
- shutdown: []
14
+ shutdown: [],
15
+ stopped: []
15
16
  }
16
17
  }.freeze
17
18
 
18
19
  attr_accessor :active_job_queue_name_prefixing, :cache_visibility_timeout, :groups,
19
20
  :launcher_executor,
20
- :start_callback, :stop_callback, :worker_executor, :worker_registry
21
+ :start_callback, :stop_callback, :worker_executor, :worker_registry, :exception_handlers
21
22
  attr_writer :default_worker_options, :sqs_client
22
23
  attr_reader :sqs_client_receive_message_opts
23
24
 
24
25
  def initialize
25
26
  self.groups = {}
26
27
  self.worker_registry = DefaultWorkerRegistry.new
28
+ self.exception_handlers = [DefaultExceptionHandler]
27
29
  self.active_job_queue_name_prefixing = false
28
30
  self.worker_executor = Worker::DefaultExecutor
29
31
  self.cache_visibility_timeout = false
@@ -134,7 +136,7 @@ module Shoryuken
134
136
  end
135
137
 
136
138
  # Register a block to run at a point in the Shoryuken lifecycle.
137
- # :startup, :quiet or :shutdown are valid events.
139
+ # :startup, :quiet, :shutdown or :stopped are valid events.
138
140
  #
139
141
  # Shoryuken.configure_server do |config|
140
142
  # config.on(:shutdown) do
@@ -22,8 +22,7 @@ module Shoryuken
22
22
  end
23
23
  end
24
24
  rescue Exception => ex
25
- logger.error { "Processor failed: #{ex.message}" }
26
- logger.error { ex.backtrace.join("\n") } unless ex.backtrace.nil?
25
+ Array(Shoryuken.exception_handlers).each { |handler| handler.call(ex, queue, sqs_msg) }
27
26
 
28
27
  raise
29
28
  end
@@ -30,9 +30,6 @@ module Shoryuken
30
30
 
31
31
  loader = EnvironmentLoader.setup_options(options)
32
32
 
33
- # When cli args exist, override options in config file
34
- Shoryuken.options.merge!(options)
35
-
36
33
  daemonize(Shoryuken.options)
37
34
  write_pid(Shoryuken.options)
38
35
 
@@ -1,3 +1,3 @@
1
1
  module Shoryuken
2
- VERSION = '5.3.2'.freeze
2
+ VERSION = '6.1.0'.freeze
3
3
  end
data/lib/shoryuken.rb CHANGED
@@ -23,6 +23,7 @@ require 'shoryuken/worker/default_executor'
23
23
  require 'shoryuken/worker/inline_executor'
24
24
  require 'shoryuken/worker_registry'
25
25
  require 'shoryuken/default_worker_registry'
26
+ require 'shoryuken/default_exception_handler'
26
27
  require 'shoryuken/middleware/chain'
27
28
  require 'shoryuken/middleware/server/auto_delete'
28
29
  Shoryuken::Middleware::Server.autoload :AutoExtendVisibility, 'shoryuken/middleware/server/auto_extend_visibility'
@@ -73,6 +74,8 @@ module Shoryuken
73
74
  :sqs_client=,
74
75
  :sqs_client_receive_message_opts,
75
76
  :sqs_client_receive_message_opts=,
77
+ :exception_handlers,
78
+ :exception_handlers=,
76
79
  :options,
77
80
  :logger,
78
81
  :register_worker,
data/shoryuken.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ['Pablo Cantero']
10
10
  spec.email = ['pablo@pablocantero.com']
11
11
  spec.description = spec.summary = 'Shoryuken is a super efficient AWS SQS thread based message processor'
12
- spec.homepage = 'https://github.com/phstc/shoryuken'
12
+ spec.homepage = 'https://github.com/ruby-shoryuken/shoryuken'
13
13
  spec.license = 'LGPL-3.0'
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0")
@@ -42,9 +42,11 @@ RSpec.shared_examples 'active_job_adapters' do
42
42
  context 'when fifo' do
43
43
  let(:fifo) { true }
44
44
 
45
- it 'does not include job_id in the deduplication_id' do
45
+ it 'does not include job_id and enqueued_at in the deduplication_id' do
46
46
  expect(queue).to receive(:send_message) do |hash|
47
- message_deduplication_id = Digest::SHA256.hexdigest(JSON.dump(job.serialize.except('job_id')))
47
+ message_deduplication_id = Digest::SHA256.hexdigest(
48
+ JSON.dump(job.serialize.except('job_id', 'enqueued_at'))
49
+ )
48
50
 
49
51
  expect(hash[:message_deduplication_id]).to eq(message_deduplication_id)
50
52
  end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ # rubocop:disable Metrics/BlockLength
4
+ RSpec.describe Shoryuken::DefaultExceptionHandler do
5
+ class CustomErrorHandler
6
+ extend Shoryuken::Util
7
+
8
+ def self.call(_ex, queue, _msg)
9
+ logger.error("#{queue.to_s} failed to process the message")
10
+ end
11
+ end
12
+
13
+ before do
14
+ Shoryuken.worker_executor = Shoryuken::Worker::InlineExecutor
15
+ allow(manager).to receive(:async).and_return(manager)
16
+ allow(manager).to receive(:real_thread)
17
+ allow(Shoryuken::Client).to receive(:queues).with(queue).and_return(sqs_queue)
18
+ end
19
+
20
+ after do
21
+ Shoryuken.worker_executor = Shoryuken::Worker::DefaultExecutor
22
+ end
23
+
24
+ let(:manager) { double Shoryuken::Manager }
25
+ let(:sqs_queue) { double Shoryuken::Queue, visibility_timeout: 30 }
26
+ let(:queue) { 'default' }
27
+
28
+ let(:sqs_msg) do
29
+ double(
30
+ Shoryuken::Message,
31
+ queue_url: queue,
32
+ body: 'test',
33
+ message_attributes: {},
34
+ message_id: SecureRandom.uuid,
35
+ receipt_handle: SecureRandom.uuid
36
+ )
37
+ end
38
+
39
+ subject { Shoryuken::Processor.new(queue, sqs_msg) }
40
+
41
+ context "with default handler" do
42
+ before do
43
+ Shoryuken.exception_handlers = described_class
44
+ end
45
+
46
+ it "logs an error message" do
47
+ expect(Shoryuken::Logging.logger).to receive(:error).twice
48
+
49
+ allow_any_instance_of(TestWorker).to receive(:perform).and_raise(StandardError, "error")
50
+ allow(sqs_msg).to receive(:body)
51
+
52
+ expect { subject.process }.to raise_error(StandardError)
53
+ end
54
+ end
55
+
56
+ context "with custom handler" do
57
+ before do
58
+ Shoryuken.exception_handlers = [described_class, CustomErrorHandler]
59
+ end
60
+
61
+ it "logs default and custom error messages" do
62
+ expect(Shoryuken::Logging.logger).to receive(:error).twice
63
+ expect(Shoryuken::Logging.logger).to receive(:error).with("default failed to process the message").once
64
+
65
+ allow_any_instance_of(TestWorker).to receive(:perform).and_raise(StandardError, "error")
66
+ allow(sqs_msg).to receive(:body)
67
+
68
+ expect { subject.process }.to raise_error(StandardError)
69
+ end
70
+ end
71
+ end
@@ -36,7 +36,7 @@ RSpec.describe Shoryuken::EnvironmentLoader do
36
36
 
37
37
  describe '#parse_queues loads default queues' do
38
38
  before do
39
- allow(subject).to receive(:load_rails)
39
+ allow(subject).to receive(:initialize_rails)
40
40
  allow(subject).to receive(:prefix_active_job_queue_names)
41
41
  allow(subject).to receive(:require_workers)
42
42
  allow(subject).to receive(:validate_queues)
@@ -54,7 +54,7 @@ RSpec.describe Shoryuken::EnvironmentLoader do
54
54
 
55
55
  describe '#parse_queues includes delay per groups' do
56
56
  before do
57
- allow(subject).to receive(:load_rails)
57
+ allow(subject).to receive(:initialize_rails)
58
58
  allow(subject).to receive(:prefix_active_job_queue_names)
59
59
  allow(subject).to receive(:require_workers)
60
60
  allow(subject).to receive(:validate_queues)
@@ -76,7 +76,7 @@ RSpec.describe Shoryuken::EnvironmentLoader do
76
76
 
77
77
  describe '#prefix_active_job_queue_names' do
78
78
  before do
79
- allow(subject).to receive(:load_rails)
79
+ allow(subject).to receive(:initialize_rails)
80
80
  allow(subject).to receive(:require_workers)
81
81
  allow(subject).to receive(:validate_queues)
82
82
  allow(subject).to receive(:validate_workers)
@@ -18,7 +18,7 @@ RSpec.describe ActiveJob::Base do
18
18
  end
19
19
 
20
20
  describe '#perform_now' do
21
- it 'allows keyward args' do
21
+ it 'allows keyword args' do
22
22
  collaborator = double 'worker collaborator'
23
23
  subject.send(:define_method, :perform) do |**kwargs|
24
24
  collaborator.foo(**kwargs)
@@ -28,12 +28,12 @@ RSpec.describe Shoryuken::Fetcher do
28
28
 
29
29
  Shoryuken.sqs_client_receive_message_opts[group] = { wait_time_seconds: 10 }
30
30
 
31
- expect(queue).to receive(:receive_messages).with(
31
+ expect(queue).to receive(:receive_messages).with({
32
32
  wait_time_seconds: 10,
33
33
  max_number_of_messages: limit,
34
34
  message_attribute_names: ['All'],
35
35
  attribute_names: ['All']
36
- ).and_return([])
36
+ }).and_return([])
37
37
 
38
38
  subject.fetch(queue_config, limit)
39
39
  end
@@ -62,11 +62,11 @@ RSpec.describe Shoryuken::Fetcher do
62
62
 
63
63
  Shoryuken.sqs_client_receive_message_opts[queue_name] = { max_number_of_messages: 1 }
64
64
 
65
- expect(queue).to receive(:receive_messages).with(
65
+ expect(queue).to receive(:receive_messages).with({
66
66
  max_number_of_messages: 1,
67
67
  message_attribute_names: ['All'],
68
68
  attribute_names: ['All']
69
- ).and_return([])
69
+ }).and_return([])
70
70
 
71
71
  subject.fetch(queue_config, limit)
72
72
  end
@@ -78,11 +78,11 @@ RSpec.describe Shoryuken::Fetcher do
78
78
 
79
79
  Shoryuken.sqs_client_receive_message_opts[queue_name] = { max_number_of_messages: 20 }
80
80
 
81
- expect(queue).to receive(:receive_messages).with(
81
+ expect(queue).to receive(:receive_messages).with({
82
82
  max_number_of_messages: limit,
83
83
  message_attribute_names: ['All'],
84
84
  attribute_names: ['All']
85
- ).and_return([])
85
+ }).and_return([])
86
86
 
87
87
  subject.fetch(queue_config, limit)
88
88
  end
@@ -93,9 +93,9 @@ RSpec.describe Shoryuken::Fetcher do
93
93
 
94
94
  specify do
95
95
  allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
96
- expect(queue).to receive(:receive_messages).with(
96
+ expect(queue).to receive(:receive_messages).with({
97
97
  max_number_of_messages: described_class::FETCH_LIMIT, attribute_names: ['All'], message_attribute_names: ['All']
98
- ).and_return([])
98
+ }).and_return([])
99
99
 
100
100
  subject.fetch(queue_config, limit)
101
101
  end
@@ -109,9 +109,9 @@ RSpec.describe Shoryuken::Fetcher do
109
109
  # see https://github.com/phstc/shoryuken/pull/530
110
110
 
111
111
  allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
112
- expect(queue).to receive(:receive_messages).with(
112
+ expect(queue).to receive(:receive_messages).with({
113
113
  max_number_of_messages: 1, attribute_names: ['All'], message_attribute_names: ['All']
114
- ).and_return([])
114
+ }).and_return([])
115
115
 
116
116
  subject.fetch(queue_config, limit)
117
117
  end
@@ -123,9 +123,9 @@ RSpec.describe Shoryuken::Fetcher do
123
123
  allow(Shoryuken::Client).to receive(:queues).with(queue_name).and_return(queue)
124
124
  allow(Shoryuken.worker_registry).to receive(:batch_receive_messages?).with(queue.name).and_return(true)
125
125
 
126
- expect(queue).to receive(:receive_messages).with(
126
+ expect(queue).to receive(:receive_messages).with({
127
127
  max_number_of_messages: limit, attribute_names: ['All'], message_attribute_names: ['All']
128
- ).and_return([])
128
+ }).and_return([])
129
129
 
130
130
  subject.fetch(queue_config, limit)
131
131
  end
@@ -57,4 +57,49 @@ RSpec.describe Shoryuken::Launcher do
57
57
  end
58
58
  end
59
59
  end
60
- end
60
+
61
+ describe '#stop' do
62
+ before do
63
+ allow(first_group_manager).to receive(:stop_new_dispatching)
64
+ allow(first_group_manager).to receive(:await_dispatching_in_progress)
65
+ allow(second_group_manager).to receive(:stop_new_dispatching)
66
+ allow(second_group_manager).to receive(:await_dispatching_in_progress)
67
+ end
68
+
69
+ it 'fires quiet, shutdown and stopped event' do
70
+ allow(subject).to receive(:fire_event)
71
+ subject.stop
72
+ expect(subject).to have_received(:fire_event).with(:quiet, true)
73
+ expect(subject).to have_received(:fire_event).with(:shutdown, true)
74
+ expect(subject).to have_received(:fire_event).with(:stopped)
75
+ end
76
+
77
+ it 'stops the managers' do
78
+ subject.stop
79
+ expect(first_group_manager).to have_received(:stop_new_dispatching)
80
+ expect(second_group_manager).to have_received(:stop_new_dispatching)
81
+ end
82
+ end
83
+
84
+ describe '#stop!' do
85
+ before do
86
+ allow(first_group_manager).to receive(:stop_new_dispatching)
87
+ allow(first_group_manager).to receive(:await_dispatching_in_progress)
88
+ allow(second_group_manager).to receive(:stop_new_dispatching)
89
+ allow(second_group_manager).to receive(:await_dispatching_in_progress)
90
+ end
91
+
92
+ it 'fires shutdown and stopped event' do
93
+ allow(subject).to receive(:fire_event)
94
+ subject.stop!
95
+ expect(subject).to have_received(:fire_event).with(:shutdown, true)
96
+ expect(subject).to have_received(:fire_event).with(:stopped)
97
+ end
98
+
99
+ it 'stops the managers' do
100
+ subject.stop!
101
+ expect(first_group_manager).to have_received(:stop_new_dispatching)
102
+ expect(second_group_manager).to have_received(:stop_new_dispatching)
103
+ end
104
+ end
105
+ end
@@ -73,9 +73,11 @@ RSpec.describe Shoryuken::Manager do
73
73
  expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
74
74
  expect(subject).to receive(:fire_event).with(:utilization_update,
75
75
  false,
76
- group: 'default',
77
- busy_processors: 1,
78
- max_processors: 1)
76
+ {
77
+ group: 'default',
78
+ busy_processors: 1,
79
+ max_processors: 1
80
+ })
79
81
  expect(Shoryuken::Processor).to receive(:process).with(q, message)
80
82
  expect(Shoryuken.logger).to receive(:info).never
81
83
 
@@ -106,9 +108,11 @@ RSpec.describe Shoryuken::Manager do
106
108
  expect(fetcher).to receive(:fetch).with(q, described_class::BATCH_LIMIT).and_return(messages)
107
109
  expect(subject).to receive(:fire_event).with(:utilization_update,
108
110
  false,
109
- group: 'default',
110
- busy_processors: 1,
111
- max_processors: 1)
111
+ {
112
+ group: 'default',
113
+ busy_processors: 1,
114
+ max_processors: 1
115
+ })
112
116
  expect(subject).to receive(:fire_event).with(:dispatch, false, queue_name: q.name)
113
117
  allow(subject).to receive(:batched_queue?).with(q).and_return(true)
114
118
  expect(Shoryuken::Processor).to receive(:process).with(q, messages)
@@ -80,7 +80,8 @@ RSpec.describe Shoryuken::Queue do
80
80
  end
81
81
 
82
82
  it 'deletes' do
83
- expect(sqs).to receive(:delete_message_batch).with(entries: entries, queue_url: queue_url).and_return(double(failed: []))
83
+ expect(sqs).to receive(:delete_message_batch).with({ entries: entries,
84
+ queue_url: queue_url }).and_return(double(failed: []))
84
85
 
85
86
  subject.delete_messages(entries: entries)
86
87
  end
@@ -91,7 +92,8 @@ RSpec.describe Shoryuken::Queue do
91
92
  logger = double 'Logger'
92
93
 
93
94
  expect(sqs).to(
94
- receive(:delete_message_batch).with(entries: entries, queue_url: queue_url).and_return(double(failed: [failure]))
95
+ receive(:delete_message_batch).with({ entries: entries,
96
+ queue_url: queue_url }).and_return(double(failed: [failure]))
95
97
  )
96
98
  expect(subject).to receive(:logger).and_return(logger)
97
99
  expect(logger).to receive(:error)
@@ -157,7 +159,8 @@ RSpec.describe Shoryuken::Queue do
157
159
  it 'accepts SQS request parameters' do
158
160
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/Client.html#send_message_batch-instance_method
159
161
  expect(sqs).to(
160
- receive(:send_message_batch).with(hash_including(entries: [{ id: '0', message_body: 'msg1' }, { id: '1', message_body: 'msg2' }]))
162
+ receive(:send_message_batch).with(hash_including(entries: [{ id: '0', message_body: 'msg1' },
163
+ { id: '1', message_body: 'msg2' }]))
161
164
  )
162
165
 
163
166
  subject.send_messages(entries: [{ id: '0', message_body: 'msg1' }, { id: '1', message_body: 'msg2' }])
@@ -286,7 +289,8 @@ RSpec.describe Shoryuken::Queue do
286
289
  Shoryuken.cache_visibility_timeout = false
287
290
 
288
291
  expect(sqs).to(
289
- receive(:get_queue_attributes).with(queue_url: queue_url, attribute_names: ['All']).and_return(attribute_response).exactly(3).times
292
+ receive(:get_queue_attributes).with(queue_url: queue_url,
293
+ attribute_names: ['All']).and_return(attribute_response).exactly(3).times
290
294
  )
291
295
  expect(subject.visibility_timeout).to eq(30)
292
296
  expect(subject.visibility_timeout).to eq(30)
@@ -299,7 +303,8 @@ RSpec.describe Shoryuken::Queue do
299
303
  Shoryuken.cache_visibility_timeout = true
300
304
 
301
305
  expect(sqs).to(
302
- receive(:get_queue_attributes).with(queue_url: queue_url, attribute_names: ['All']).and_return(attribute_response).once
306
+ receive(:get_queue_attributes).with({ queue_url: queue_url,
307
+ attribute_names: ['All'] }).and_return(attribute_response).once
303
308
  )
304
309
  expect(subject.visibility_timeout).to eq(30)
305
310
  expect(subject.visibility_timeout).to eq(30)
@@ -10,16 +10,16 @@ RSpec.describe Shoryuken::Worker::DefaultExecutor do
10
10
 
11
11
  describe '.perform_in' do
12
12
  it 'delays a message' do
13
- expect(sqs_queue).to receive(:send_message).with(
14
- message_attributes: {
15
- 'shoryuken_class' => {
16
- string_value: TestWorker.to_s,
17
- data_type: 'String'
18
- }
19
- },
20
- message_body: 'message',
21
- delay_seconds: 60
22
- )
13
+ expect(sqs_queue).to receive(:send_message).with({
14
+ message_attributes: {
15
+ 'shoryuken_class' => {
16
+ string_value: TestWorker.to_s,
17
+ data_type: 'String'
18
+ }
19
+ },
20
+ message_body: 'message',
21
+ delay_seconds: 60
22
+ })
23
23
 
24
24
  TestWorker.perform_in(60, 'message')
25
25
  end
@@ -33,16 +33,16 @@ RSpec.describe Shoryuken::Worker::DefaultExecutor do
33
33
 
34
34
  describe '.perform_at' do
35
35
  it 'delays a message' do
36
- expect(sqs_queue).to receive(:send_message).with(
37
- message_attributes: {
38
- 'shoryuken_class' => {
39
- string_value: TestWorker.to_s,
40
- data_type: 'String'
41
- }
42
- },
43
- message_body: 'message',
44
- delay_seconds: 60
45
- )
36
+ expect(sqs_queue).to receive(:send_message).with({
37
+ message_attributes: {
38
+ 'shoryuken_class' => {
39
+ string_value: TestWorker.to_s,
40
+ data_type: 'String'
41
+ }
42
+ },
43
+ message_body: 'message',
44
+ delay_seconds: 60
45
+ })
46
46
 
47
47
  TestWorker.perform_in(Time.now + 60, 'message')
48
48
  end
@@ -56,30 +56,30 @@ RSpec.describe Shoryuken::Worker::DefaultExecutor do
56
56
 
57
57
  describe '.perform_async' do
58
58
  it 'enqueues a message' do
59
- expect(sqs_queue).to receive(:send_message).with(
60
- message_attributes: {
61
- 'shoryuken_class' => {
62
- string_value: TestWorker.to_s,
63
- data_type: 'String'
64
- }
65
- },
66
- message_body: 'message'
67
- )
59
+ expect(sqs_queue).to receive(:send_message).with({
60
+ message_attributes: {
61
+ 'shoryuken_class' => {
62
+ string_value: TestWorker.to_s,
63
+ data_type: 'String'
64
+ }
65
+ },
66
+ message_body: 'message'
67
+ })
68
68
 
69
69
  TestWorker.perform_async('message')
70
70
  end
71
71
 
72
72
  it 'enqueues a message with options' do
73
- expect(sqs_queue).to receive(:send_message).with(
74
- delay_seconds: 60,
75
- message_attributes: {
76
- 'shoryuken_class' => {
77
- string_value: TestWorker.to_s,
78
- data_type: 'String'
79
- }
80
- },
81
- message_body: 'delayed message'
82
- )
73
+ expect(sqs_queue).to receive(:send_message).with({
74
+ delay_seconds: 60,
75
+ message_attributes: {
76
+ 'shoryuken_class' => {
77
+ string_value: TestWorker.to_s,
78
+ data_type: 'String'
79
+ }
80
+ },
81
+ message_body: 'delayed message'
82
+ })
83
83
 
84
84
  TestWorker.perform_async('delayed message', delay_seconds: 60)
85
85
  end
@@ -89,15 +89,15 @@ RSpec.describe Shoryuken::Worker::DefaultExecutor do
89
89
 
90
90
  expect(Shoryuken::Client).to receive(:queues).with(new_queue).and_return(sqs_queue)
91
91
 
92
- expect(sqs_queue).to receive(:send_message).with(
93
- message_attributes: {
94
- 'shoryuken_class' => {
95
- string_value: TestWorker.to_s,
96
- data_type: 'String'
97
- }
98
- },
99
- message_body: 'delayed message'
100
- )
92
+ expect(sqs_queue).to receive(:send_message).with({
93
+ message_attributes: {
94
+ 'shoryuken_class' => {
95
+ string_value: TestWorker.to_s,
96
+ data_type: 'String'
97
+ }
98
+ },
99
+ message_body: 'delayed message'
100
+ })
101
101
 
102
102
  TestWorker.perform_async('delayed message', queue: new_queue)
103
103
  end
data/spec/spec_helper.rb CHANGED
@@ -46,6 +46,8 @@ RSpec.configure do |config|
46
46
  Shoryuken.options[:logfile] = nil
47
47
  Shoryuken.options[:queues] = nil
48
48
 
49
+ Shoryuken.options[:exception_handlers] = []
50
+
49
51
  TestWorker.get_shoryuken_options.clear
50
52
  TestWorker.get_shoryuken_options['queue'] = 'default'
51
53
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shoryuken
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.2
4
+ version: 6.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pablo Cantero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-20 00:00:00.000000000 Z
11
+ date: 2023-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -103,8 +103,13 @@ extensions: []
103
103
  extra_rdoc_files: []
104
104
  files:
105
105
  - ".codeclimate.yml"
106
+ - ".devcontainer/Dockerfile"
107
+ - ".devcontainer/base.Dockerfile"
108
+ - ".devcontainer/devcontainer.json"
106
109
  - ".github/FUNDING.yml"
110
+ - ".github/dependabot.yml"
107
111
  - ".github/workflows/specs.yml"
112
+ - ".github/workflows/stale.yml"
108
113
  - ".gitignore"
109
114
  - ".reek.yml"
110
115
  - ".rspec"
@@ -126,10 +131,12 @@ files:
126
131
  - gemfiles/rails_5_2.gemfile
127
132
  - gemfiles/rails_6_0.gemfile
128
133
  - gemfiles/rails_6_1.gemfile
134
+ - gemfiles/rails_7_0.gemfile
129
135
  - lib/shoryuken.rb
130
136
  - lib/shoryuken/body_parser.rb
131
137
  - lib/shoryuken/client.rb
132
138
  - lib/shoryuken/core_ext.rb
139
+ - lib/shoryuken/default_exception_handler.rb
133
140
  - lib/shoryuken/default_worker_registry.rb
134
141
  - lib/shoryuken/environment_loader.rb
135
142
  - lib/shoryuken/extensions/active_job_adapter.rb
@@ -167,6 +174,7 @@ files:
167
174
  - spec/shoryuken/body_parser_spec.rb
168
175
  - spec/shoryuken/client_spec.rb
169
176
  - spec/shoryuken/core_ext_spec.rb
177
+ - spec/shoryuken/default_exception_handler_spec.rb
170
178
  - spec/shoryuken/default_worker_registry_spec.rb
171
179
  - spec/shoryuken/environment_loader_spec.rb
172
180
  - spec/shoryuken/extensions/active_job_adapter_spec.rb
@@ -195,7 +203,7 @@ files:
195
203
  - spec/spec_helper.rb
196
204
  - test_workers/endless_interruptive_worker.rb
197
205
  - test_workers/endless_uninterruptive_worker.rb
198
- homepage: https://github.com/phstc/shoryuken
206
+ homepage: https://github.com/ruby-shoryuken/shoryuken
199
207
  licenses:
200
208
  - LGPL-3.0
201
209
  metadata: {}
@@ -214,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
222
  - !ruby/object:Gem::Version
215
223
  version: '0'
216
224
  requirements: []
217
- rubygems_version: 3.0.3.1
225
+ rubygems_version: 3.3.26
218
226
  signing_key:
219
227
  specification_version: 4
220
228
  summary: Shoryuken is a super efficient AWS SQS thread based message processor
@@ -225,6 +233,7 @@ test_files:
225
233
  - spec/shoryuken/body_parser_spec.rb
226
234
  - spec/shoryuken/client_spec.rb
227
235
  - spec/shoryuken/core_ext_spec.rb
236
+ - spec/shoryuken/default_exception_handler_spec.rb
228
237
  - spec/shoryuken/default_worker_registry_spec.rb
229
238
  - spec/shoryuken/environment_loader_spec.rb
230
239
  - spec/shoryuken/extensions/active_job_adapter_spec.rb