shoryuken 5.0.6 → 5.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae01acd8276e60e8ff9a8dfbd9eab999c31899741fd8b5ed1f91edd36f1bec7e
4
- data.tar.gz: ca4774bd1a58c1706556308a753885b182bbf72006316b6a711d8b9025bca9de
3
+ metadata.gz: 313fe407e7c7715e8a83bd3fcef713cb5755d31e9d94345fe26157c823f4b156
4
+ data.tar.gz: 53890b5dc5dcf0d12fd5153b459d9cb317dace747d95516f754bd320be7eb105
5
5
  SHA512:
6
- metadata.gz: 12b5a07474ea1acff314443e4ab3e0d267976089cc9cb088c8c1b21f0a6240728c9fe4ae520413c53d13d01064a7f4f052920c7329809511cd980556a8208eef
7
- data.tar.gz: 5dd806a0993c3f09f523a0cb52597bafb8da4219144470cc7059a44785e70ca51a7d47e886590838ea439ddddf6ea96230d623f93c8a3db466ae924f23e3b8da
6
+ metadata.gz: b349de0985d3beac244ed9f1b8886c7b71e18a810936d1cf1e89baddff507ee5b83af100a598653976ba8e337f0e8ad25f3db6b178b6bbd544e9696772b63160
7
+ data.tar.gz: 92ef7d6d5648485c1556225a81e6808d6ba127342e3edcb93cacb10e4f1070077f40f6b5ec3b9a1809226e092eb99c2710c2d238c4f16ea3072455f83c2eb643
@@ -0,0 +1,57 @@
1
+ name: Specs
2
+
3
+ on:
4
+ - push
5
+ - pull_request
6
+
7
+ jobs:
8
+ all_specs:
9
+ name: All Specs
10
+ strategy:
11
+ matrix:
12
+ ruby: ['2.4.4', '2.5.1', '2.6.3']
13
+ gemfile: ['Gemfile', 'Gemfile.aws-sdk-core-v2']
14
+ runs-on: ubuntu-20.04
15
+ env:
16
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v2
20
+ - uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby }}
23
+ bundler-cache: true
24
+ - name: Run specs
25
+ env:
26
+ SPEC_ALL: true
27
+ run: bundle exec rake spec
28
+ rails_specs:
29
+ name: Rails Specs
30
+ strategy:
31
+ matrix:
32
+ rails: ['4.2', '5.2', '6.0', '6.1']
33
+ include:
34
+ - rails: '4.2'
35
+ ruby: '2.2'
36
+ gemfile: gemfiles/rails_4_2.gemfile
37
+ - rails: '5.2'
38
+ ruby: '2.5'
39
+ gemfile: gemfiles/rails_5_2.gemfile
40
+ - rails: '6.0'
41
+ ruby: '2.6'
42
+ gemfile: gemfiles/rails_6_0.gemfile
43
+ - rails: '6.1'
44
+ ruby: '3.0'
45
+ gemfile: gemfiles/rails_6_1.gemfile
46
+ runs-on: ubuntu-20.04
47
+ env:
48
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
49
+ steps:
50
+ - name: Checkout code
51
+ uses: actions/checkout@v2
52
+ - uses: ruby/setup-ruby@v1
53
+ with:
54
+ ruby-version: ${{ matrix.ruby }}
55
+ bundler-cache: true
56
+ - name: Run Rails specs
57
+ run: bundle exec rake rails_specs
data/.reek.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ detectors:
3
+
4
+ UtilityFunction:
5
+ public_methods_only: true
data/Appraisals ADDED
@@ -0,0 +1,28 @@
1
+ appraise 'rails_4_2' do
2
+ group :test do
3
+ gem 'activejob', '~> 4.2'
4
+ end
5
+
6
+ group :development do
7
+ gem 'appraisal', '~> 2.2'
8
+ remove_gem 'pry-byebug'
9
+ end
10
+ end
11
+
12
+ appraise 'rails_5_2' do
13
+ group :test do
14
+ gem 'activejob', '~> 5.2'
15
+ end
16
+ end
17
+
18
+ appraise 'rails_6_0' do
19
+ group :test do
20
+ gem 'activejob', '~> 6.0'
21
+ end
22
+ end
23
+
24
+ appraise 'rails_6_1' do
25
+ group :test do
26
+ gem 'activejob', '~> 6.1'
27
+ end
28
+ end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## [v5.1.0] - 2021-02-06
2
+
3
+ - Add support for specifying SQS SendMessage parameters with ActiveJob `.set`
4
+ - [#635](https://github.com/phstc/shoryuken/pull/635)
5
+ - [#648](https://github.com/phstc/shoryuken/pull/648)
6
+ - [#651](https://github.com/phstc/shoryuken/pull/651)
7
+
8
+ - Unpause FIFO queues on worker completion
9
+ - [#644](https://github.com/phstc/shoryuken/pull/644)
10
+
11
+ - Add multiple versions of Rails to test matrix
12
+ - [#647](https://github.com/phstc/shoryuken/pull/647)
13
+
14
+ - Migrate from Travis CI to Github Actions
15
+ - [#649](https://github.com/phstc/shoryuken/pull/649)
16
+ - [#650](https://github.com/phstc/shoryuken/pull/650)
17
+ - [#652](https://github.com/phstc/shoryuken/pull/652)
18
+
1
19
  ## [v5.0.6] - 2020-12-30
2
20
 
3
21
  - Load ShoryukenConcurrentSendAdapter when loading Rails
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :test do
7
- gem 'activejob', '~> 4'
7
+ gem 'activejob'
8
8
  gem 'aws-sdk-core', '~> 3'
9
9
  gem 'aws-sdk-sqs'
10
10
  gem 'codeclimate-test-reporter', require: nil
@@ -14,5 +14,7 @@ group :test do
14
14
  end
15
15
 
16
16
  group :development do
17
+ gem 'appraisal', git: 'https://github.com/thoughtbot/appraisal.git'
18
+ gem 'pry-byebug', '3.9.0'
17
19
  gem 'rubocop'
18
20
  end
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  Shoryuken _sho-ryu-ken_ is a super-efficient [Amazon SQS](https://aws.amazon.com/sqs/) thread-based message processor.
8
8
 
9
- [![Build Status](https://travis-ci.org/phstc/shoryuken.svg)](https://travis-ci.org/phstc/shoryuken)
9
+ [![Build Status](https://github.com/ruby-shoryuken/shoryuken/workflows/Specs/badge.svg)](https://github.com/ruby-shoryuken/shoryuken/actions)
10
10
  [![Code Climate](https://codeclimate.com/github/phstc/shoryuken/badges/gpa.svg)](https://codeclimate.com/github/phstc/shoryuken)
11
11
 
12
12
  ## Key features
@@ -66,3 +66,17 @@ For more information check the [wiki page](https://github.com/phstc/shoryuken/wi
66
66
  3. Commit your changes (`git commit -am 'Add some feature'`)
67
67
  4. Push to the branch (`git push origin my-new-feature`)
68
68
  5. Create a new Pull Request
69
+
70
+ ### Testing
71
+
72
+ To run all specs against the latest dependency vesions, execute
73
+
74
+ ```sh
75
+ bundle exec rake spec
76
+ ```
77
+
78
+ To run all Rails-related specs against all supported versions of Rails, execute
79
+
80
+ ```sh
81
+ bundle exec appraisal rake rails_specs
82
+ ```
data/Rakefile CHANGED
@@ -4,6 +4,9 @@ $stdout.sync = true
4
4
  begin
5
5
  require 'rspec/core/rake_task'
6
6
  RSpec::Core::RakeTask.new(:spec)
7
+
8
+ rails_task = RSpec::Core::RakeTask.new(:rails_specs)
9
+ rails_task.pattern = 'spec/shoryuken/{environment_loader_spec,extensions/active_job_*}.rb'
7
10
  rescue LoadError
8
11
  end
9
12
 
@@ -0,0 +1 @@
1
+ *.gemfile.lock
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ group :test do
6
+ gem "activejob", "~> 4.2"
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", "~> 2.2"
17
+ gem "rubocop"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -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", "~> 5.2"
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 "pry-byebug", "3.9.0"
18
+ gem "rubocop"
19
+ end
20
+
21
+ gemspec path: "../"
@@ -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", "~> 6.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 "pry-byebug", "3.9.0"
18
+ gem "rubocop"
19
+ end
20
+
21
+ gemspec path: "../"
@@ -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", "~> 6.1"
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 "pry-byebug", "3.9.0"
18
+ gem "rubocop"
19
+ end
20
+
21
+ gemspec path: "../"
data/lib/shoryuken.rb CHANGED
@@ -89,6 +89,7 @@ module Shoryuken
89
89
  end
90
90
 
91
91
  if Shoryuken.active_job?
92
+ require 'shoryuken/extensions/active_job_extensions'
92
93
  require 'shoryuken/extensions/active_job_adapter'
93
94
  require 'shoryuken/extensions/active_job_concurrent_send_adapter'
94
95
  end
@@ -71,6 +71,7 @@ module Shoryuken
71
71
  end
72
72
  end
73
73
  if Shoryuken.active_job?
74
+ require 'shoryuken/extensions/active_job_extensions'
74
75
  require 'shoryuken/extensions/active_job_adapter'
75
76
  require 'shoryuken/extensions/active_job_concurrent_send_adapter'
76
77
  end
@@ -33,8 +33,12 @@ module ActiveJob
33
33
  def enqueue(job, options = {}) #:nodoc:
34
34
  register_worker!(job)
35
35
 
36
+ job.sqs_send_message_parameters.merge! options
37
+
36
38
  queue = Shoryuken::Client.queues(job.queue_name)
37
- queue.send_message(message(queue, job, options))
39
+ send_message_params = message queue, job
40
+ job.sqs_send_message_parameters = send_message_params
41
+ queue.send_message send_message_params
38
42
  end
39
43
 
40
44
  def enqueue_at(job, timestamp) #:nodoc:
@@ -50,35 +54,29 @@ module ActiveJob
50
54
  delay
51
55
  end
52
56
 
53
- def message(queue, job, options = {})
57
+ def message(queue, job)
54
58
  body = job.serialize
59
+ job_params = job.sqs_send_message_parameters
60
+
61
+ attributes = job_params[:message_attributes] || {}
55
62
 
56
- msg = {}
63
+ msg = {
64
+ message_body: body,
65
+ message_attributes: attributes.merge(MESSAGE_ATTRIBUTES)
66
+ }
57
67
 
58
68
  if queue.fifo?
59
69
  # See https://github.com/phstc/shoryuken/issues/457
60
70
  msg[:message_deduplication_id] = Digest::SHA256.hexdigest(JSON.dump(body.except('job_id')))
61
71
  end
62
72
 
63
- msg[:message_body] = body
64
- msg[:message_attributes] = message_attributes
65
-
66
- msg.merge(options)
73
+ msg.merge(job_params.except(:message_attributes))
67
74
  end
68
75
 
69
76
  def register_worker!(job)
70
77
  Shoryuken.register_worker(job.queue_name, JobWrapper)
71
78
  end
72
79
 
73
- def message_attributes
74
- @message_attributes ||= {
75
- 'shoryuken_class' => {
76
- string_value: JobWrapper.to_s,
77
- data_type: 'String'
78
- }
79
- }
80
- end
81
-
82
80
  class JobWrapper #:nodoc:
83
81
  include Shoryuken::Worker
84
82
 
@@ -88,6 +86,13 @@ module ActiveJob
88
86
  Base.execute hash
89
87
  end
90
88
  end
89
+
90
+ MESSAGE_ATTRIBUTES = {
91
+ 'shoryuken_class' => {
92
+ string_value: JobWrapper.to_s,
93
+ data_type: 'String'
94
+ }
95
+ }.freeze
91
96
  end
92
97
  end
93
98
  end
@@ -0,0 +1,37 @@
1
+ module Shoryuken
2
+ module ActiveJobExtensions
3
+ # Adds an accessor for SQS SendMessage parameters on ActiveJob jobs
4
+ # (instances of ActiveJob::Base). Shoryuken ActiveJob queue adapters use
5
+ # these parameters when enqueueing jobs; other adapters can ignore them.
6
+ module SQSSendMessageParametersAccessor
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ attr_accessor :sqs_send_message_parameters
11
+ end
12
+ end
13
+
14
+ # Initializes SQS SendMessage parameters on instances of ActiveJobe::Base
15
+ # to the empty hash, and populates it whenever `#enqueue` is called, such
16
+ # as when using ActiveJob::Base.set.
17
+ module SQSSendMessageParametersSupport
18
+ def initialize(*arguments)
19
+ super(*arguments)
20
+ self.sqs_send_message_parameters = {}
21
+ end
22
+
23
+ def enqueue(options = {})
24
+ sqs_options = options.extract! :message_attributes,
25
+ :message_system_attributes,
26
+ :message_deduplication_id,
27
+ :message_group_id
28
+ sqs_send_message_parameters.merge! sqs_options
29
+
30
+ super
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ ActiveJob::Base.include Shoryuken::ActiveJobExtensions::SQSSendMessageParametersAccessor
37
+ ActiveJob::Base.prepend Shoryuken::ActiveJobExtensions::SQSSendMessageParametersSupport
@@ -57,8 +57,13 @@ module Shoryuken
57
57
  @max_processors - busy
58
58
  end
59
59
 
60
- def processor_done
60
+ def processor_done(queue)
61
61
  @busy_processors.decrement
62
+ client_queue = Shoryuken::Client.queues(queue)
63
+ return unless client_queue.fifo?
64
+ return unless @polling_strategy.respond_to?(:message_processed)
65
+
66
+ @polling_strategy.message_processed(queue)
62
67
  end
63
68
 
64
69
  def assign(queue_name, sqs_msg)
@@ -68,9 +73,10 @@ module Shoryuken
68
73
 
69
74
  @busy_processors.increment
70
75
 
71
- Concurrent::Promise.execute(
72
- executor: @executor
73
- ) { Processor.process(queue_name, sqs_msg) }.then { processor_done }.rescue { processor_done }
76
+ Concurrent::Promise
77
+ .execute(executor: @executor) { Processor.process(queue_name, sqs_msg) }
78
+ .then { processor_done(queue_name) }
79
+ .rescue { processor_done(queue_name) }
74
80
  end
75
81
 
76
82
  def dispatch_batch(queue)
@@ -40,6 +40,8 @@ module Shoryuken
40
40
  fail NotImplementedError
41
41
  end
42
42
 
43
+ def message_processed(_queue); end
44
+
43
45
  def active_queues
44
46
  fail NotImplementedError
45
47
  end
@@ -38,6 +38,11 @@ module Shoryuken
38
38
  .reverse
39
39
  end
40
40
 
41
+ def message_processed(queue)
42
+ logger.debug "Unpausing #{queue}"
43
+ @paused_until[queue] = Time.now
44
+ end
45
+
41
46
  private
42
47
 
43
48
  def next_active_queue
@@ -70,6 +75,7 @@ module Shoryuken
70
75
 
71
76
  def pause(queue)
72
77
  return unless delay > 0
78
+
73
79
  @paused_until[queue] = Time.now + delay
74
80
  logger.debug "Paused #{queue}"
75
81
  end
@@ -35,10 +35,20 @@ module Shoryuken
35
35
  unparse_queues(@queues)
36
36
  end
37
37
 
38
+ def message_processed(queue)
39
+ return if @paused_queues.empty?
40
+
41
+ logger.debug "Unpausing #{queue}"
42
+ @paused_queues.reject! { |_time, name| name == queue }
43
+ @queues << queue
44
+ @queues.uniq!
45
+ end
46
+
38
47
  private
39
48
 
40
49
  def pause(queue)
41
50
  return unless @queues.delete(queue)
51
+
42
52
  @paused_queues << [Time.now + delay, queue]
43
53
  logger.debug "Paused #{queue}"
44
54
  end
@@ -46,6 +56,7 @@ module Shoryuken
46
56
  def unpause_queues
47
57
  return if @paused_queues.empty?
48
58
  return if Time.now < @paused_queues.first[0]
59
+
49
60
  pause = @paused_queues.shift
50
61
  @queues << pause[1]
51
62
  logger.debug "Unpaused #{pause[1]}"
@@ -1,3 +1,3 @@
1
1
  module Shoryuken
2
- VERSION = '5.0.6'.freeze
2
+ VERSION = '5.1.0'.freeze
3
3
  end
data/shoryuken.gemspec CHANGED
@@ -18,7 +18,6 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ['lib']
19
19
 
20
20
  spec.add_development_dependency 'dotenv'
21
- spec.add_development_dependency 'pry-byebug', '3.9.0'
22
21
  spec.add_development_dependency 'rake'
23
22
  spec.add_development_dependency 'rspec'
24
23
 
@@ -1,30 +1,44 @@
1
+ require 'active_job'
2
+ require 'shoryuken/extensions/active_job_extensions'
3
+
4
+ # Stand-in for a job class specified by the user
5
+ class TestJob < ActiveJob::Base; end
6
+
1
7
  # rubocop:disable Metrics/BlockLength
2
8
  RSpec.shared_examples 'active_job_adapters' do
3
- let(:job) { double 'Job', id: '123', queue_name: 'queue' }
9
+ let(:job_sqs_send_message_parameters) { {} }
10
+ let(:job) do
11
+ job = TestJob.new
12
+ job.sqs_send_message_parameters = job_sqs_send_message_parameters
13
+ job
14
+ end
4
15
  let(:fifo) { false }
5
16
  let(:queue) { double 'Queue', fifo?: fifo }
6
17
 
7
18
  before do
8
19
  allow(Shoryuken::Client).to receive(:queues).with(job.queue_name).and_return(queue)
9
- allow(job).to receive(:serialize).and_return(
10
- 'job_class' => 'Worker',
11
- 'job_id' => job.id,
12
- 'queue_name' => job.queue_name,
13
- 'arguments' => nil,
14
- 'locale' => nil
15
- )
16
20
  end
17
21
 
18
22
  describe '#enqueue' do
19
23
  specify do
20
24
  expect(queue).to receive(:send_message) do |hash|
21
25
  expect(hash[:message_deduplication_id]).to_not be
26
+ expect(hash[:message_attributes]['shoryuken_class'][:string_value]).to eq(described_class::JobWrapper.to_s)
27
+ expect(hash[:message_attributes]['shoryuken_class'][:data_type]).to eq("String")
28
+ expect(hash[:message_attributes].keys).to eq(['shoryuken_class'])
22
29
  end
23
30
  expect(Shoryuken).to receive(:register_worker).with(job.queue_name, described_class::JobWrapper)
24
31
 
25
32
  subject.enqueue(job)
26
33
  end
27
34
 
35
+ it "should mutate the job's sqs_send_message_parameters reference to match those sent to the queue" do
36
+ expect(queue).to receive(:send_message) do |options|
37
+ expect(options).to be(job.sqs_send_message_parameters)
38
+ end
39
+ subject.enqueue(job)
40
+ end
41
+
28
42
  context 'when fifo' do
29
43
  let(:fifo) { true }
30
44
 
@@ -38,6 +52,209 @@ RSpec.shared_examples 'active_job_adapters' do
38
52
 
39
53
  subject.enqueue(job)
40
54
  end
55
+
56
+ context 'with message_deduplication_id' do
57
+ context 'when message_deduplication_id is specified in options' do
58
+ it 'should enqueue a message with the deduplication_id specified in options' do
59
+ expect(queue).to receive(:send_message) do |hash|
60
+ expect(hash[:message_deduplication_id]).to eq('options-dedupe-id')
61
+ end
62
+ subject.enqueue(job, message_deduplication_id: 'options-dedupe-id')
63
+ end
64
+ end
65
+
66
+ context 'when message_deduplication_id is specified on the job' do
67
+ let(:job_sqs_send_message_parameters) { { message_deduplication_id: 'job-dedupe-id' } }
68
+
69
+ it 'should enqueue a message with the deduplication_id specified on the job' do
70
+ expect(queue).to receive(:send_message) do |hash|
71
+ expect(hash[:message_deduplication_id]).to eq('job-dedupe-id')
72
+ end
73
+ subject.enqueue job
74
+ end
75
+ end
76
+
77
+ context 'when message_deduplication_id is specified on the job and also in options' do
78
+ let(:job_sqs_send_message_parameters) { { message_deduplication_id: 'job-dedupe-id' } }
79
+
80
+ it 'should enqueue a message with the deduplication_id specified in options' do
81
+ expect(queue).to receive(:send_message) do |hash|
82
+ expect(hash[:message_deduplication_id]).to eq('options-dedupe-id')
83
+ end
84
+ subject.enqueue(job, message_deduplication_id: 'options-dedupe-id')
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ context 'with message_group_id' do
91
+ context 'when message_group_id is specified in options' do
92
+ it 'should enqueue a message with the group_id specified in options' do
93
+ expect(queue).to receive(:send_message) do |hash|
94
+ expect(hash[:message_group_id]).to eq('options-group-id')
95
+ end
96
+ subject.enqueue(job, message_group_id: 'options-group-id')
97
+ end
98
+ end
99
+
100
+ context 'when message_group_id is specified on the job' do
101
+ let(:job_sqs_send_message_parameters) { { message_group_id: 'job-group-id' } }
102
+
103
+ it 'should enqueue a message with the group_id specified on the job' do
104
+ expect(queue).to receive(:send_message) do |hash|
105
+ expect(hash[:message_group_id]).to eq('job-group-id')
106
+ end
107
+ subject.enqueue job
108
+ end
109
+ end
110
+
111
+ context 'when message_group_id is specified on the job and also in options' do
112
+ let(:job_sqs_send_message_parameters) { { message_group_id: 'job-group-id' } }
113
+
114
+ it 'should enqueue a message with the group_id specified in options' do
115
+ expect(queue).to receive(:send_message) do |hash|
116
+ expect(hash[:message_group_id]).to eq('options-group-id')
117
+ end
118
+ subject.enqueue(job, message_group_id: 'options-group-id')
119
+ end
120
+ end
121
+ end
122
+
123
+ context 'with additional message attributes' do
124
+ it 'should combine with activejob attributes' do
125
+ custom_message_attributes = {
126
+ 'tracer_id' => {
127
+ string_value: SecureRandom.hex,
128
+ data_type: 'String'
129
+ }
130
+ }
131
+
132
+ expect(queue).to receive(:send_message) do |hash|
133
+ expect(hash[:message_attributes]['shoryuken_class'][:string_value]).to eq(described_class::JobWrapper.to_s)
134
+ expect(hash[:message_attributes]['shoryuken_class'][:data_type]).to eq("String")
135
+ expect(hash[:message_attributes]['tracer_id'][:string_value]).to eq(custom_message_attributes['tracer_id'][:string_value])
136
+ expect(hash[:message_attributes]['tracer_id'][:data_type]).to eq("String")
137
+ end
138
+ expect(Shoryuken).to receive(:register_worker).with(job.queue_name, described_class::JobWrapper)
139
+
140
+ subject.enqueue(job, message_attributes: custom_message_attributes)
141
+ end
142
+
143
+ context 'when message_attributes are specified on the job' do
144
+ let(:job_sqs_send_message_parameters) do
145
+ {
146
+ message_attributes: {
147
+ 'tracer_id' => {
148
+ data_type: 'String',
149
+ string_value: 'job-value'
150
+ }
151
+ }
152
+ }
153
+ end
154
+
155
+ it 'should enqueue a message with the message_attributes specified on the job' do
156
+ expect(queue).to receive(:send_message) do |hash|
157
+ expect(hash[:message_attributes]['tracer_id']).to eq({ data_type: 'String', string_value: 'job-value' })
158
+ expect(hash[:message_attributes]['shoryuken_class']).to eq({ data_type: 'String', string_value: described_class::JobWrapper.to_s })
159
+ end
160
+ subject.enqueue job
161
+ end
162
+ end
163
+
164
+ context 'when message_attributes are specified on the job and also in options' do
165
+ let(:job_sqs_send_message_parameters) do
166
+ {
167
+ message_attributes: {
168
+ 'tracer_id' => {
169
+ data_type: 'String',
170
+ string_value: 'job-value'
171
+ }
172
+ }
173
+ }
174
+ end
175
+
176
+ it 'should enqueue a message with the message_attributes speficied in options' do
177
+ custom_message_attributes = {
178
+ 'options_tracer_id' => {
179
+ string_value: 'options-value',
180
+ data_type: 'String'
181
+ }
182
+ }
183
+
184
+ expect(queue).to receive(:send_message) do |hash|
185
+ expect(hash[:message_attributes]['tracer_id']).to be_nil
186
+ expect(hash[:message_attributes]['options_tracer_id']).to eq({ data_type: 'String', string_value: 'options-value' })
187
+ expect(hash[:message_attributes]['shoryuken_class']).to eq({ data_type: 'String', string_value: described_class::JobWrapper.to_s })
188
+ end
189
+ subject.enqueue job, message_attributes: custom_message_attributes
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ context 'with message_system_attributes' do
196
+ context 'when message_system_attributes are specified in options' do
197
+ it 'should enqueue a message with message_system_attributes specified in options' do
198
+ system_attributes = {
199
+ 'AWSTraceHeader' => {
200
+ string_value: 'trace_id',
201
+ data_type: 'String'
202
+ }
203
+ }
204
+ expect(queue).to receive(:send_message) do |hash|
205
+ expect(hash[:message_system_attributes]['AWSTraceHeader'][:string_value]).to eq('trace_id')
206
+ expect(hash[:message_system_attributes]['AWSTraceHeader'][:data_type]).to eq('String')
207
+ end
208
+ subject.enqueue(job, message_system_attributes: system_attributes)
209
+ end
210
+ end
211
+
212
+ context 'when message_system_attributes are specified on the job' do
213
+ let(:job_sqs_send_message_parameters) do
214
+ {
215
+ message_system_attributes: {
216
+ 'AWSTraceHeader' => {
217
+ string_value: 'job-value',
218
+ data_type: 'String'
219
+ }
220
+ }
221
+ }
222
+ end
223
+
224
+ it 'should enqueue a message with the message_system_attributes specified on the job' do
225
+ expect(queue).to receive(:send_message) do |hash|
226
+ expect(hash[:message_system_attributes]['AWSTraceHeader']).to eq({ data_type: 'String', string_value: 'job-value' })
227
+ end
228
+ subject.enqueue job
229
+ end
230
+ end
231
+
232
+ context 'when message_system_attributes are specified on the job and also in options' do
233
+ let(:job_sqs_send_message_parameters) do
234
+ {
235
+ message_system_attributes: {
236
+ 'job_trace_header' => {
237
+ string_value: 'job-value',
238
+ data_type: 'String'
239
+ }
240
+ }
241
+ }
242
+ end
243
+
244
+ it 'should enqueue a message with the message_system_attributes speficied in options' do
245
+ custom_message_attributes = {
246
+ 'options_trace_header' => {
247
+ string_value: 'options-value',
248
+ data_type: 'String'
249
+ }
250
+ }
251
+
252
+ expect(queue).to receive(:send_message) do |hash|
253
+ expect(hash[:message_system_attributes]['job_trace_header']).to be_nil
254
+ expect(hash[:message_system_attributes]['options_trace_header']).to eq({ data_type: 'String', string_value: 'options-value' })
255
+ end
256
+ subject.enqueue job, message_system_attributes: custom_message_attributes
257
+ end
41
258
  end
42
259
  end
43
260
 
@@ -59,4 +276,4 @@ RSpec.shared_examples 'active_job_adapters' do
59
276
  end
60
277
  end
61
278
  end
62
- # rubocop:enable Metrics/BlockLength
279
+ # rubocop:enable Metrics/BlockLength
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
- require 'shoryuken/extensions/active_job_adapter'
3
2
  require 'shared_examples_for_active_job'
3
+ require 'shoryuken/extensions/active_job_adapter'
4
4
 
5
5
  RSpec.describe ActiveJob::QueueAdapters::ShoryukenAdapter do
6
6
  include_examples 'active_job_adapters'
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+ require 'active_job'
3
+ require 'shoryuken/extensions/active_job_extensions'
4
+ require 'shoryuken/extensions/active_job_adapter'
5
+
6
+ RSpec.describe ActiveJob::Base do
7
+ let(:queue_adapter) { ActiveJob::QueueAdapters::ShoryukenAdapter.new }
8
+
9
+ subject do
10
+ worker_class = Class.new(described_class)
11
+ Object.const_set :MyWorker, worker_class
12
+ worker_class.queue_adapter = queue_adapter
13
+ worker_class
14
+ end
15
+
16
+ after do
17
+ Object.send :remove_const, :MyWorker
18
+ end
19
+
20
+ describe '#perform_later' do
21
+ it 'calls enqueue on the adapter with the expected job' do
22
+ expect(queue_adapter).to receive(:enqueue) do |job|
23
+ expect(job.arguments).to eq([1, 2])
24
+ end
25
+
26
+ subject.perform_later 1, 2
27
+ end
28
+
29
+ it 'passes message_group_id to the queue_adapter' do
30
+ expect(queue_adapter).to receive(:enqueue) do |job|
31
+ expect(job.sqs_send_message_parameters[:message_group_id]).to eq('group-2')
32
+ end
33
+
34
+ subject.set(message_group_id: 'group-2').perform_later 1, 2
35
+ end
36
+
37
+ it 'passes message_deduplication_id to the queue_adapter' do
38
+ expect(queue_adapter).to receive(:enqueue) do |job|
39
+ expect(job.sqs_send_message_parameters[:message_deduplication_id]).to eq('dedupe-id')
40
+ end
41
+
42
+ subject.set(message_deduplication_id: 'dedupe-id').perform_later 1, 2
43
+ end
44
+
45
+ it 'passes message_attributes to the queue_adapter' do
46
+ message_attributes = {
47
+ 'custom_tracing_id' => {
48
+ string_value: 'value',
49
+ data_type: 'String'
50
+ }
51
+ }
52
+ expect(queue_adapter).to receive(:enqueue) do |job|
53
+ expect(job.sqs_send_message_parameters[:message_attributes]).to eq(message_attributes)
54
+ end
55
+
56
+ subject.set(message_attributes: message_attributes).perform_later 1, 2
57
+ end
58
+
59
+ it 'passes message_system_attributes to the queue_adapter' do
60
+ message_system_attributes = {
61
+ 'AWSTraceHeader' => {
62
+ string_value: 'trace_id',
63
+ data_type: 'String'
64
+ }
65
+ }
66
+ expect(queue_adapter).to receive(:enqueue) do |job|
67
+ expect(job.sqs_send_message_parameters[:message_system_attributes]).to eq(message_system_attributes)
68
+ end
69
+
70
+ subject.set(message_system_attributes: message_system_attributes).perform_later 1, 2
71
+ end
72
+ end
73
+ end
@@ -139,4 +139,28 @@ RSpec.describe Shoryuken::Manager do
139
139
  subject.send(:dispatch_single_messages, q)
140
140
  end
141
141
  end
142
+
143
+ describe '#processor_done' do
144
+ let(:sqs_queue) { double Shoryuken::Queue }
145
+
146
+ before do
147
+ allow(Shoryuken::Client).to receive(:queues).with(queue).and_return(sqs_queue)
148
+ end
149
+
150
+ context 'when queue.fifo? is true' do
151
+ it 'calls message_processed on strategy' do
152
+ expect(sqs_queue).to receive(:fifo?).and_return(true)
153
+ expect(polling_strategy).to receive(:message_processed).with(queue)
154
+ subject.send(:processor_done, queue)
155
+ end
156
+ end
157
+
158
+ context 'when queue.fifo? is false' do
159
+ it 'does not call message_processed on strategy' do
160
+ expect(sqs_queue).to receive(:fifo?).and_return(false)
161
+ expect(polling_strategy).to_not receive(:message_processed)
162
+ subject.send(:processor_done, queue)
163
+ end
164
+ end
165
+ end
142
166
  end
@@ -145,4 +145,14 @@ RSpec.describe Shoryuken::Polling::StrictPriority do
145
145
  expect(subject.next_queue).to eq(queue3)
146
146
  end
147
147
  end
148
+
149
+ describe '#message_processed' do
150
+ it 'removes paused queue, adds to active queues' do
151
+ strategy = Shoryuken::Polling::StrictPriority.new([queue1, queue2])
152
+ strategy.send(:pause, queue1)
153
+ expect(strategy.active_queues).to eq([[queue2, 1]])
154
+ strategy.message_processed(queue1)
155
+ expect(strategy.active_queues).to eq([[queue1, 2], [queue2, 1]])
156
+ end
157
+ end
148
158
  end
@@ -104,4 +104,14 @@ RSpec.describe Shoryuken::Polling::WeightedRoundRobin do
104
104
  expect(subject.delay).to eq(1.0)
105
105
  end
106
106
  end
107
+
108
+ describe '#message_processed' do
109
+ it 'removes paused queue, adds to active queues' do
110
+ strategy = Shoryuken::Polling::WeightedRoundRobin.new([queue1, queue2])
111
+ strategy.send(:pause, queue1)
112
+ expect(strategy.active_queues).to eq([[queue2, 1]])
113
+ strategy.message_processed(queue1)
114
+ expect(strategy.active_queues).to eq([[queue2, 1], [queue1, 1]])
115
+ end
116
+ end
107
117
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,11 @@
1
1
  require 'bundler/setup'
2
2
  Bundler.setup
3
3
 
4
- require 'pry-byebug'
4
+ begin
5
+ require 'pry-byebug'
6
+ rescue LoadError
7
+ end
8
+
5
9
  require 'shoryuken'
6
10
  require 'json'
7
11
  require 'dotenv'
@@ -28,11 +32,7 @@ class TestWorker
28
32
  end
29
33
 
30
34
  RSpec.configure do |config|
31
- # Only run slow tests if SPEC_ALL=true and AWS_ACCESS_KEY_ID is present
32
- # The AWS_ACCESS_KEY_ID checker is because Travis CI
33
- # does not expose ENV variables to pull requests from forked repositories
34
- # http://docs.travis-ci.com/user/pull-requests/
35
- # config.filter_run_excluding slow: true if ENV['SPEC_ALL'] != 'true' || ENV['AWS_ACCESS_KEY_ID'].nil?
35
+ # TODO: Run these tests again on CI
36
36
  config.filter_run_excluding slow: true
37
37
 
38
38
  config.before do
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.0.6
4
+ version: 5.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: 2020-12-30 00:00:00.000000000 Z
11
+ date: 2021-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: pry-byebug
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '='
32
- - !ruby/object:Gem::Version
33
- version: 3.9.0
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '='
39
- - !ruby/object:Gem::Version
40
- version: 3.9.0
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -118,10 +104,12 @@ extra_rdoc_files: []
118
104
  files:
119
105
  - ".codeclimate.yml"
120
106
  - ".github/FUNDING.yml"
107
+ - ".github/workflows/specs.yml"
121
108
  - ".gitignore"
109
+ - ".reek.yml"
122
110
  - ".rspec"
123
111
  - ".rubocop.yml"
124
- - ".travis.yml"
112
+ - Appraisals
125
113
  - CHANGELOG.md
126
114
  - Gemfile
127
115
  - Gemfile.aws-sdk-core-v2
@@ -133,6 +121,11 @@ files:
133
121
  - bin/shoryuken
134
122
  - examples/bootstrap_queues.rb
135
123
  - examples/default_worker.rb
124
+ - gemfiles/.gitignore
125
+ - gemfiles/rails_4_2.gemfile
126
+ - gemfiles/rails_5_2.gemfile
127
+ - gemfiles/rails_6_0.gemfile
128
+ - gemfiles/rails_6_1.gemfile
136
129
  - lib/shoryuken.rb
137
130
  - lib/shoryuken/body_parser.rb
138
131
  - lib/shoryuken/client.rb
@@ -141,6 +134,7 @@ files:
141
134
  - lib/shoryuken/environment_loader.rb
142
135
  - lib/shoryuken/extensions/active_job_adapter.rb
143
136
  - lib/shoryuken/extensions/active_job_concurrent_send_adapter.rb
137
+ - lib/shoryuken/extensions/active_job_extensions.rb
144
138
  - lib/shoryuken/fetcher.rb
145
139
  - lib/shoryuken/launcher.rb
146
140
  - lib/shoryuken/logging.rb
@@ -176,6 +170,7 @@ files:
176
170
  - spec/shoryuken/default_worker_registry_spec.rb
177
171
  - spec/shoryuken/environment_loader_spec.rb
178
172
  - spec/shoryuken/extensions/active_job_adapter_spec.rb
173
+ - spec/shoryuken/extensions/active_job_base_spec.rb
179
174
  - spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb
180
175
  - spec/shoryuken/fetcher_spec.rb
181
176
  - spec/shoryuken/manager_spec.rb
@@ -217,8 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
212
  - !ruby/object:Gem::Version
218
213
  version: '0'
219
214
  requirements: []
220
- rubyforge_project:
221
- rubygems_version: 2.7.6
215
+ rubygems_version: 3.0.1
222
216
  signing_key:
223
217
  specification_version: 4
224
218
  summary: Shoryuken is a super efficient AWS SQS thread based message processor
@@ -232,6 +226,7 @@ test_files:
232
226
  - spec/shoryuken/default_worker_registry_spec.rb
233
227
  - spec/shoryuken/environment_loader_spec.rb
234
228
  - spec/shoryuken/extensions/active_job_adapter_spec.rb
229
+ - spec/shoryuken/extensions/active_job_base_spec.rb
235
230
  - spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb
236
231
  - spec/shoryuken/fetcher_spec.rb
237
232
  - spec/shoryuken/manager_spec.rb
data/.travis.yml DELETED
@@ -1,30 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - 2.4.4
5
- - 2.5.1
6
- - 2.6.3
7
-
8
- notifications:
9
- email:
10
- on_success: change
11
- on_failure: always
12
-
13
- gemfile:
14
- - Gemfile
15
- - Gemfile.aws-sdk-core-v2
16
-
17
- env:
18
- - SPEC_ALL=true
19
-
20
- script: bundle exec rspec spec
21
-
22
- before_install:
23
- - gem install bundler -v '< 2'
24
-
25
- after_success:
26
- - bundle exec codeclimate-test-reporter
27
-
28
- addons:
29
- code_climate:
30
- repo_token: 7709fd21981bb9d2658647a66d959415a1029a83f1c199573828797944f26c52