shoryuken 5.0.6 → 5.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/specs.yml +62 -0
  3. data/.reek.yml +5 -0
  4. data/Appraisals +28 -0
  5. data/CHANGELOG.md +48 -0
  6. data/Gemfile +3 -1
  7. data/README.md +21 -1
  8. data/Rakefile +15 -1
  9. data/bin/cli/sqs.rb +50 -5
  10. data/gemfiles/.gitignore +1 -0
  11. data/gemfiles/rails_4_2.gemfile +20 -0
  12. data/gemfiles/rails_5_2.gemfile +21 -0
  13. data/gemfiles/rails_6_0.gemfile +21 -0
  14. data/gemfiles/rails_6_1.gemfile +21 -0
  15. data/lib/shoryuken.rb +1 -0
  16. data/lib/shoryuken/environment_loader.rb +3 -0
  17. data/lib/shoryuken/extensions/active_job_adapter.rb +25 -18
  18. data/lib/shoryuken/extensions/active_job_extensions.rb +38 -0
  19. data/lib/shoryuken/manager.rb +10 -4
  20. data/lib/shoryuken/polling/base.rb +2 -0
  21. data/lib/shoryuken/polling/strict_priority.rb +6 -0
  22. data/lib/shoryuken/polling/weighted_round_robin.rb +11 -0
  23. data/lib/shoryuken/version.rb +1 -1
  24. data/shoryuken.gemspec +0 -1
  25. data/spec/integration/launcher_spec.rb +29 -2
  26. data/spec/shared_examples_for_active_job.rb +226 -9
  27. data/spec/shoryuken/environment_loader_spec.rb +22 -2
  28. data/spec/shoryuken/extensions/active_job_adapter_spec.rb +1 -1
  29. data/spec/shoryuken/extensions/active_job_base_spec.rb +84 -0
  30. data/spec/shoryuken/extensions/active_job_concurrent_send_adapter_spec.rb +4 -0
  31. data/spec/shoryuken/extensions/active_job_wrapper_spec.rb +20 -0
  32. data/spec/shoryuken/manager_spec.rb +24 -0
  33. data/spec/shoryuken/polling/strict_priority_spec.rb +10 -0
  34. data/spec/shoryuken/polling/weighted_round_robin_spec.rb +10 -0
  35. data/spec/spec_helper.rb +5 -9
  36. metadata +16 -19
  37. data/.travis.yml +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae01acd8276e60e8ff9a8dfbd9eab999c31899741fd8b5ed1f91edd36f1bec7e
4
- data.tar.gz: ca4774bd1a58c1706556308a753885b182bbf72006316b6a711d8b9025bca9de
3
+ metadata.gz: 32f81ad9c6c98fde2b6056ba4675787369e6a324652913ca0250a3c721f6940a
4
+ data.tar.gz: e7cd7dc155525904147b89bcdb6ffa8e984459d8553c0b53aae7f74ceaf4dcb0
5
5
  SHA512:
6
- metadata.gz: 12b5a07474ea1acff314443e4ab3e0d267976089cc9cb088c8c1b21f0a6240728c9fe4ae520413c53d13d01064a7f4f052920c7329809511cd980556a8208eef
7
- data.tar.gz: 5dd806a0993c3f09f523a0cb52597bafb8da4219144470cc7059a44785e70ca51a7d47e886590838ea439ddddf6ea96230d623f93c8a3db466ae924f23e3b8da
6
+ metadata.gz: b8fc8971739f98a6107f7bc9dd47a35082ae7dfbf21e3bc2f57827fa3466a923cff49f92576b99642a64351eca80511ed29d6ace8a49063131e30d905424c4af
7
+ data.tar.gz: b8b11252d270c00cae4d8ca87949aebb93aef83411767def3adb6651ba6707a4f9964fc4c968e6ddf469f68cf51bc9f474961c31e074da70319626e6fe4d2dc9
@@ -0,0 +1,62 @@
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
+ services:
16
+ moto_sqs:
17
+ image: quay.io/cjlarose/moto-sqs-server:1.1.0
18
+ ports:
19
+ - 5000:5000
20
+ env:
21
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
22
+ steps:
23
+ - name: Checkout code
24
+ uses: actions/checkout@v2
25
+ - uses: ruby/setup-ruby@v1
26
+ with:
27
+ ruby-version: ${{ matrix.ruby }}
28
+ bundler-cache: true
29
+ - name: Run specs
30
+ run: bundle exec rake spec
31
+ - name: Run integration specs
32
+ run: bundle exec rake spec:integration
33
+ rails_specs:
34
+ name: Rails Specs
35
+ strategy:
36
+ matrix:
37
+ rails: ['4.2', '5.2', '6.0', '6.1']
38
+ include:
39
+ - rails: '4.2'
40
+ ruby: '2.2'
41
+ gemfile: gemfiles/rails_4_2.gemfile
42
+ - rails: '5.2'
43
+ ruby: '2.5'
44
+ gemfile: gemfiles/rails_5_2.gemfile
45
+ - rails: '6.0'
46
+ ruby: '2.6'
47
+ gemfile: gemfiles/rails_6_0.gemfile
48
+ - rails: '6.1'
49
+ ruby: '3.0'
50
+ gemfile: gemfiles/rails_6_1.gemfile
51
+ runs-on: ubuntu-20.04
52
+ env:
53
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
54
+ steps:
55
+ - name: Checkout code
56
+ uses: actions/checkout@v2
57
+ - uses: ruby/setup-ruby@v1
58
+ with:
59
+ ruby-version: ${{ matrix.ruby }}
60
+ bundler-cache: true
61
+ - name: Run Rails specs
62
+ run: bundle exec rake spec:rails
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,51 @@
1
+ ## [v5.2.2] - 2021-06-22
2
+
3
+ - When using ActiveJob queue name prefixing, avoid applying prefix to queues configured with a URL or ARN
4
+ - [#667](https://github.com/ruby-shoryuken/shoryuken/pull/667)
5
+
6
+ ## [v5.2.1] - 2021-04-06
7
+
8
+ - Reduce message batch sizes in `shoryuken sqs requeue` and `shoryuken sqs mv` commands
9
+ - [#666](https://github.com/ruby-shoryuken/shoryuken/pull/666)
10
+
11
+ - Fix bug in `shoryuken sqs requeue` and `shoryuken sqs mv` where those commands would exceed the SQS `SendMessageBatch` maximum payload size
12
+ - [#663](https://github.com/ruby-shoryuken/shoryuken/issues/663)
13
+ - [#664](https://github.com/ruby-shoryuken/shoryuken/pull/664)
14
+
15
+ - Remove test stub for `Concurrent.global_io_executor`
16
+ - [#662](https://github.com/ruby-shoryuken/shoryuken/pull/662)
17
+
18
+ - Run integration tests on CI
19
+ - [#660](https://github.com/ruby-shoryuken/shoryuken/pull/660)
20
+
21
+ ## [v5.2.0] - 2021-02-26
22
+
23
+ - Set `executions` correctly for ActiveJob jobs
24
+ - [#657](https://github.com/phstc/shoryuken/pull/657)
25
+
26
+ ## [v5.1.1] - 2021-02-10
27
+
28
+ - Fix regression in Ruby 3.0 introduced in Shoryuken 5.1.0, where enqueueing jobs with ActiveJob to workers that used keyword arguments would fail
29
+ - [#654](https://github.com/phstc/shoryuken/pull/654)
30
+
31
+ ## [v5.1.0] - 2021-02-06
32
+
33
+ - Add support for specifying SQS SendMessage parameters with ActiveJob `.set`
34
+ - [#635](https://github.com/phstc/shoryuken/pull/635)
35
+ - [#648](https://github.com/phstc/shoryuken/pull/648)
36
+ - [#651](https://github.com/phstc/shoryuken/pull/651)
37
+
38
+ - Unpause FIFO queues on worker completion
39
+ - [#644](https://github.com/phstc/shoryuken/pull/644)
40
+
41
+ - Add multiple versions of Rails to test matrix
42
+ - [#647](https://github.com/phstc/shoryuken/pull/647)
43
+
44
+ - Migrate from Travis CI to Github Actions
45
+ - [#649](https://github.com/phstc/shoryuken/pull/649)
46
+ - [#650](https://github.com/phstc/shoryuken/pull/650)
47
+ - [#652](https://github.com/phstc/shoryuken/pull/652)
48
+
1
49
  ## [v5.0.6] - 2020-12-30
2
50
 
3
51
  - 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,23 @@ 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 unit 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 spec:rails
82
+ ```
83
+
84
+ To run integration specs, start a mock SQS server on `localhost:5000`. One such option is [cjlarose/moto-sqs-server](https://github.com/cjlarose/moto-sqs-server). Then execute
85
+
86
+ ```sh
87
+ bundle exec rake spec:integration
88
+ ```
data/Rakefile CHANGED
@@ -3,7 +3,21 @@ $stdout.sync = true
3
3
 
4
4
  begin
5
5
  require 'rspec/core/rake_task'
6
- RSpec::Core::RakeTask.new(:spec)
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.exclude_pattern = 'spec/integration/**/*_spec.rb'
8
+ end
9
+
10
+ namespace :spec do
11
+ desc 'Run Rails specs only'
12
+ RSpec::Core::RakeTask.new(:rails) do |t|
13
+ t.pattern = 'spec/shoryuken/{environment_loader_spec,extensions/active_job_*}.rb'
14
+ end
15
+
16
+ desc 'Run integration specs only'
17
+ RSpec::Core::RakeTask.new(:integration) do |t|
18
+ t.pattern = 'spec/integration/**/*_spec.rb'
19
+ end
20
+ end
7
21
  rescue LoadError
8
22
  end
9
23
 
data/bin/cli/sqs.rb CHANGED
@@ -4,6 +4,9 @@ require 'date'
4
4
  module Shoryuken
5
5
  module CLI
6
6
  class SQS < Base
7
+ # See https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/quotas-messages.html
8
+ MAX_BATCH_SIZE = 256 * 1024
9
+
7
10
  namespace :sqs
8
11
  class_option :endpoint, aliases: '-e', type: :string, default: ENV['SHORYUKEN_SQS_ENDPOINT'], desc: 'Endpoint URL'
9
12
 
@@ -51,14 +54,56 @@ module Shoryuken
51
54
  end
52
55
  end
53
56
 
54
- def batch_send(url, messages, messages_per_batch = 10)
55
- messages.to_a.flatten.map(&method(:normalize_dump_message)).each_slice(messages_per_batch) do |batch|
56
- sqs.send_message_batch(queue_url: url, entries: batch).failed.any? do |failure|
57
- say "Could not requeue #{failure.id}, code: #{failure.code}", :yellow
57
+ def batch_send(url, messages, max_batch_size = 10)
58
+ messages = messages.to_a.flatten.map(&method(:normalize_dump_message))
59
+ batch_send_normalized_messages url, messages, max_batch_size
60
+ end
61
+
62
+ def batch_send_normalized_messages(url, messages, max_batch_size)
63
+ # Repeatedly take the longest prefix of messages such that
64
+ # 1. The number of messages is less than or equal to max_batch_size
65
+ # 2. The total message payload size is less than or equal to the
66
+ # batch payload limit
67
+ while messages.size.positive?
68
+ batch_size = max_batch_size
69
+ loop do
70
+ batch = messages.take batch_size
71
+
72
+ unless batch.size == 1 || batch_payload_size(batch) <= MAX_BATCH_SIZE
73
+ batch_size = batch.size - 1
74
+ next
75
+ end
76
+
77
+ sqs.send_message_batch(queue_url: url, entries: batch).failed.any? do |failure|
78
+ say "Could not requeue #{failure.id}, code: #{failure.code}", :yellow
79
+ end
80
+ messages = messages.drop batch.size
81
+ break
58
82
  end
59
83
  end
60
84
  end
61
85
 
86
+ def batch_payload_size(messages)
87
+ messages.sum(&method(:message_size))
88
+ end
89
+
90
+ def message_size(message)
91
+ attribute_size = (message[:message_attributes] || []).sum do |name, value|
92
+ name_size = name.to_s.bytesize
93
+ data_type_size = value[:data_type].bytesize
94
+ value_size = if value[:string_value]
95
+ value[:string_value].bytesize
96
+ elsif value[:binary_value]
97
+ value[:binary_value].bytesize
98
+ end
99
+ name_size + data_type_size + value_size
100
+ end
101
+
102
+ body_size = message[:message_body].bytesize
103
+
104
+ attribute_size + body_size
105
+ end
106
+
62
107
  def find_all(url, limit)
63
108
  count = 0
64
109
  batch_size = limit > 10 ? 10 : limit
@@ -160,7 +205,7 @@ module Shoryuken
160
205
  end
161
206
 
162
207
  desc 'requeue QUEUE-NAME PATH', 'Requeues messages from a dump file'
163
- method_option :batch_size, aliases: '-n', type: :numeric, default: 10, desc: 'number of messages per batch to send'
208
+ method_option :batch_size, aliases: '-n', type: :numeric, default: 10, desc: 'maximum number of messages per batch to send'
164
209
  def requeue(queue_name, path)
165
210
  fail_task "Path #{path} not found" unless File.exist?(path)
166
211
 
@@ -0,0 +1 @@
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
@@ -79,6 +80,8 @@ module Shoryuken
79
80
  end
80
81
 
81
82
  def prefix_active_job_queue_name(queue_name, weight)
83
+ return [queue_name, weight] if queue_name.start_with?('https://', 'arn:')
84
+
82
85
  queue_name_prefix = ::ActiveJob::Base.queue_name_prefix
83
86
  queue_name_delimiter = ::ActiveJob::Base.queue_name_delimiter
84
87
 
@@ -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,44 +54,47 @@ 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
 
85
83
  shoryuken_options body_parser: :json, auto_delete: true
86
84
 
87
- def perform(_sqs_msg, hash)
88
- Base.execute hash
85
+ def perform(sqs_msg, hash)
86
+ receive_count = sqs_msg.attributes['ApproximateReceiveCount'].to_i
87
+ past_receives = receive_count - 1
88
+ Base.execute hash.merge({ 'executions' => past_receives })
89
89
  end
90
90
  end
91
+
92
+ MESSAGE_ATTRIBUTES = {
93
+ 'shoryuken_class' => {
94
+ string_value: JobWrapper.to_s,
95
+ data_type: 'String'
96
+ }
97
+ }.freeze
91
98
  end
92
99
  end
93
100
  end