shoryuken 5.0.6 → 5.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: 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