From 7a0be4b717e7cc06120bc592212d98847af97138 Mon Sep 17 00:00:00 2001 From: Arnaud Lachaume Date: Mon, 31 May 2021 13:41:32 +0200 Subject: [PATCH] add support for ruby 3.0.x - fixes #27 --- .github/workflows/test_ruby_2.x.yml | 48 +++++++ .../workflows/{test.yml => test_ruby_3.x.yml} | 13 +- Appraisals | 4 + examples/rails/.ruby-version | 2 +- examples/rails/Gemfile | 6 +- examples/rails/Gemfile.lock | 134 ++++++++++-------- examples/sinatra/Gemfile | 2 +- examples/sinatra/Gemfile.lock | 96 +++++++------ gemfiles/rails_6.1.gemfile | 7 + lib/cloudtasker/backend/google_cloud_task.rb | 16 ++- lib/cloudtasker/backend/memory_task.rb | 2 +- lib/cloudtasker/backend/redis_task.rb | 10 +- lib/cloudtasker/cloud_task.rb | 4 +- lib/cloudtasker/cron/schedule.rb | 10 +- lib/cloudtasker/redis_client.rb | 53 +++++-- lib/cloudtasker/unique_job/job.rb | 5 +- .../unique_job/middleware/client.rb | 3 +- lib/cloudtasker/worker.rb | 6 +- lib/cloudtasker/worker_wrapper.rb | 2 +- .../cloudtasker_adapter/job_wrapper_spec.rb | 2 +- .../backend/google_cloud_task_spec.rb | 2 +- spec/cloudtasker/backend/memory_task_spec.rb | 10 +- spec/cloudtasker/backend/redis_task_spec.rb | 20 +-- spec/cloudtasker/cloud_task_spec.rb | 12 +- spec/cloudtasker/cron/schedule_spec.rb | 2 +- spec/cloudtasker/worker_spec.rb | 4 +- spec/cloudtasker/worker_wrapper_spec.rb | 4 +- spec/support/test_middleware.rb | 4 +- 28 files changed, 297 insertions(+), 186 deletions(-) create mode 100644 .github/workflows/test_ruby_2.x.yml rename .github/workflows/{test.yml => test_ruby_3.x.yml} (86%) create mode 100644 gemfiles/rails_6.1.gemfile diff --git a/.github/workflows/test_ruby_2.x.yml b/.github/workflows/test_ruby_2.x.yml new file mode 100644 index 00000000..47ce709e --- /dev/null +++ b/.github/workflows/test_ruby_2.x.yml @@ -0,0 +1,48 @@ +name: Ruby 2.x + +on: + push: + branches: [ master, 0.9-stable ] + pull_request: + branches: [ master, 0.9-stable ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + ruby: + - '2.5.9' + - '2.6.7' + - '2.7.3' + appraisal: + - 'google-cloud-tasks-1.0' + - 'google-cloud-tasks-1.1' + - 'google-cloud-tasks-1.2' + - 'google-cloud-tasks-1.3' + - 'rails-5.2' + - 'rails-6.0' + - 'rails-6.1' + - 'semantic_logger-3.4' + - 'semantic_logger-4.6' + - 'semantic_logger-4.7.0' + - 'semantic_logger-4.7.2' + steps: + - name: Setup System + run: sudo apt-get install libsqlite3-dev + - uses: actions/checkout@v2 + - uses: zhulik/redis-action@1.1.0 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Build and test with Rake + env: + APPRAISAL_CONTEXT: ${{ matrix.appraisal }} + run: | + gem install bundler + bundle install --jobs 4 --retry 3 + bundle exec rubocop + bundle exec appraisal ${APPRAISAL_CONTEXT} bundle + bundle exec appraisal ${APPRAISAL_CONTEXT} rspec diff --git a/.github/workflows/test.yml b/.github/workflows/test_ruby_3.x.yml similarity index 86% rename from .github/workflows/test.yml rename to .github/workflows/test_ruby_3.x.yml index c3a16fd7..1a198bcd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test_ruby_3.x.yml @@ -1,4 +1,4 @@ -name: Test +name: Ruby 3.x on: push: @@ -12,15 +12,13 @@ jobs: strategy: matrix: ruby: - - '2.5.x' - - '2.6.x' + - '3.0.1' appraisal: - 'google-cloud-tasks-1.0' - 'google-cloud-tasks-1.1' - 'google-cloud-tasks-1.2' - 'google-cloud-tasks-1.3' - - 'rails-5.2' - - 'rails-6.0' + - 'rails-6.1' - 'semantic_logger-3.4' - 'semantic_logger-4.6' - 'semantic_logger-4.7.0' @@ -30,10 +28,11 @@ jobs: run: sudo apt-get install libsqlite3-dev - uses: actions/checkout@v2 - uses: zhulik/redis-action@1.1.0 - - name: Set up Ruby 2.6 - uses: actions/setup-ruby@v1 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} + bundler-cache: true - name: Build and test with Rake env: APPRAISAL_CONTEXT: ${{ matrix.appraisal }} diff --git a/Appraisals b/Appraisals index 2735ae9d..3bea8556 100644 --- a/Appraisals +++ b/Appraisals @@ -24,6 +24,10 @@ appraise 'rails-6.0' do gem 'rails', '6.0' end +appraise 'rails-6.1' do + gem 'rails', '6.1' +end + appraise 'semantic_logger-3.4' do gem 'semantic_logger', '3.4.1' end diff --git a/examples/rails/.ruby-version b/examples/rails/.ruby-version index 80d02f91..85588beb 100644 --- a/examples/rails/.ruby-version +++ b/examples/rails/.ruby-version @@ -1 +1 @@ -ruby-2.5.5 +ruby-3.0.0 diff --git a/examples/rails/Gemfile b/examples/rails/Gemfile index 6aab9e92..b0715cb2 100644 --- a/examples/rails/Gemfile +++ b/examples/rails/Gemfile @@ -3,10 +3,12 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.5.5' +ruby '3.0.0' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.2' +gem 'rails', '~> 6.1.3' + +gem 'puma', '~> 5.3.2' # Background jobs via Cloud Tasks gem 'cloudtasker', path: '../../' diff --git a/examples/rails/Gemfile.lock b/examples/rails/Gemfile.lock index c8b3fb38..f3a43ca8 100644 --- a/examples/rails/Gemfile.lock +++ b/examples/rails/Gemfile.lock @@ -13,67 +13,72 @@ PATH GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.7) - actionpack (= 6.0.3.7) + actioncable (6.1.3.2) + actionpack (= 6.1.3.2) + activesupport (= 6.1.3.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.7) - actionpack (= 6.0.3.7) - activejob (= 6.0.3.7) - activerecord (= 6.0.3.7) - activestorage (= 6.0.3.7) - activesupport (= 6.0.3.7) + actionmailbox (6.1.3.2) + actionpack (= 6.1.3.2) + activejob (= 6.1.3.2) + activerecord (= 6.1.3.2) + activestorage (= 6.1.3.2) + activesupport (= 6.1.3.2) mail (>= 2.7.1) - actionmailer (6.0.3.7) - actionpack (= 6.0.3.7) - actionview (= 6.0.3.7) - activejob (= 6.0.3.7) + actionmailer (6.1.3.2) + actionpack (= 6.1.3.2) + actionview (= 6.1.3.2) + activejob (= 6.1.3.2) + activesupport (= 6.1.3.2) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.7) - actionview (= 6.0.3.7) - activesupport (= 6.0.3.7) - rack (~> 2.0, >= 2.0.8) + actionpack (6.1.3.2) + actionview (= 6.1.3.2) + activesupport (= 6.1.3.2) + rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.7) - actionpack (= 6.0.3.7) - activerecord (= 6.0.3.7) - activestorage (= 6.0.3.7) - activesupport (= 6.0.3.7) + actiontext (6.1.3.2) + actionpack (= 6.1.3.2) + activerecord (= 6.1.3.2) + activestorage (= 6.1.3.2) + activesupport (= 6.1.3.2) nokogiri (>= 1.8.5) - actionview (6.0.3.7) - activesupport (= 6.0.3.7) + actionview (6.1.3.2) + activesupport (= 6.1.3.2) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.7) - activesupport (= 6.0.3.7) + activejob (6.1.3.2) + activesupport (= 6.1.3.2) globalid (>= 0.3.6) - activemodel (6.0.3.7) - activesupport (= 6.0.3.7) - activerecord (6.0.3.7) - activemodel (= 6.0.3.7) - activesupport (= 6.0.3.7) - activestorage (6.0.3.7) - actionpack (= 6.0.3.7) - activejob (= 6.0.3.7) - activerecord (= 6.0.3.7) + activemodel (6.1.3.2) + activesupport (= 6.1.3.2) + activerecord (6.1.3.2) + activemodel (= 6.1.3.2) + activesupport (= 6.1.3.2) + activestorage (6.1.3.2) + actionpack (= 6.1.3.2) + activejob (= 6.1.3.2) + activerecord (= 6.1.3.2) + activesupport (= 6.1.3.2) marcel (~> 1.0.0) - activesupport (6.0.3.7) + mini_mime (~> 1.0.2) + activesupport (6.1.3.2) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) builder (3.2.4) concurrent-ruby (1.1.8) connection_pool (2.2.5) crass (1.0.6) + date (3.1.0) erubi (1.10.0) et-orbi (1.2.4) tzinfo @@ -139,7 +144,7 @@ GEM marcel (1.0.1) memoist (0.16.2) method_source (1.0.0) - mini_mime (1.1.0) + mini_mime (1.0.3) mini_portile2 (2.5.2) net-ftp (~> 0.1) minitest (5.14.4) @@ -157,37 +162,39 @@ GEM racc (~> 1.4) os (1.1.1) public_suffix (4.0.6) + puma (5.3.2) + nio4r (~> 2.0) raabro (1.4.0) racc (1.5.2) rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.7) - actioncable (= 6.0.3.7) - actionmailbox (= 6.0.3.7) - actionmailer (= 6.0.3.7) - actionpack (= 6.0.3.7) - actiontext (= 6.0.3.7) - actionview (= 6.0.3.7) - activejob (= 6.0.3.7) - activemodel (= 6.0.3.7) - activerecord (= 6.0.3.7) - activestorage (= 6.0.3.7) - activesupport (= 6.0.3.7) - bundler (>= 1.3.0) - railties (= 6.0.3.7) + rails (6.1.3.2) + actioncable (= 6.1.3.2) + actionmailbox (= 6.1.3.2) + actionmailer (= 6.1.3.2) + actionpack (= 6.1.3.2) + actiontext (= 6.1.3.2) + actionview (= 6.1.3.2) + activejob (= 6.1.3.2) + activemodel (= 6.1.3.2) + activerecord (= 6.1.3.2) + activestorage (= 6.1.3.2) + activesupport (= 6.1.3.2) + bundler (>= 1.15.0) + railties (= 6.1.3.2) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.7) - actionpack (= 6.0.3.7) - activesupport (= 6.0.3.7) + railties (6.1.3.2) + actionpack (= 6.1.3.2) + activesupport (= 6.1.3.2) method_source rake (>= 0.8.7) - thor (>= 0.20.3, < 2.0) + thor (~> 1.0) rake (13.0.3) redis (4.2.5) retriable (3.1.2) @@ -207,11 +214,11 @@ GEM sprockets (>= 3.0.0) sqlite3 (1.4.2) thor (1.1.0) - thread_safe (0.3.6) time (0.1.0) + date timeout (0.1.1) - tzinfo (1.2.9) - thread_safe (~> 0.1) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) websocket-driver (0.7.4) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -222,11 +229,12 @@ PLATFORMS DEPENDENCIES cloudtasker! - rails (~> 6.0.2) + puma (~> 5.3.2) + rails (~> 6.1.3) sqlite3 RUBY VERSION - ruby 2.5.5p157 + ruby 3.0.0p0 BUNDLED WITH 2.2.9 diff --git a/examples/sinatra/Gemfile b/examples/sinatra/Gemfile index 9681f462..baeba1c5 100644 --- a/examples/sinatra/Gemfile +++ b/examples/sinatra/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.5.5' +ruby '3.0.0' # Web framework gem 'sinatra' diff --git a/examples/sinatra/Gemfile.lock b/examples/sinatra/Gemfile.lock index b8ceed45..3e8939da 100644 --- a/examples/sinatra/Gemfile.lock +++ b/examples/sinatra/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: ../.. specs: - cloudtasker (0.10.rc8) + cloudtasker (0.12.rc10) activesupport connection_pool fugit @@ -13,23 +13,34 @@ PATH GEM remote: https://rubygems.org/ specs: - activesupport (6.0.3.2) + activesupport (6.1.3.2) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - concurrent-ruby (1.1.6) - connection_pool (2.2.3) + concurrent-ruby (1.1.8) + connection_pool (2.2.5) et-orbi (1.2.4) tzinfo - faraday (1.0.1) + faraday (1.4.2) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.1) multipart-post (>= 1.2, < 3) - fugit (1.3.6) + ruby2_keywords (>= 0.0.4) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.1.0) + fugit (1.4.5) et-orbi (~> 1.1, >= 1.1.8) - raabro (~> 1.3) + raabro (~> 1.4) google-cloud-tasks (1.5.1) google-gax (~> 1.8) googleapis-common-protos (>= 1.3.9, < 2.0) @@ -41,61 +52,60 @@ GEM googleauth (~> 0.9) grpc (~> 1.24) rly (~> 0.2.3) - google-protobuf (3.12.2) - googleapis-common-protos (1.3.10) - google-protobuf (~> 3.11) - googleapis-common-protos-types (>= 1.0.5, < 2.0) + google-protobuf (3.17.1) + googleapis-common-protos (1.3.11) + google-protobuf (~> 3.14) + googleapis-common-protos-types (>= 1.0.6, < 2.0) grpc (~> 1.27) - googleapis-common-protos-types (1.0.5) - google-protobuf (~> 3.11) - googleauth (0.13.0) + googleapis-common-protos-types (1.0.6) + google-protobuf (~> 3.14) + googleauth (0.16.2) faraday (>= 0.17.3, < 2.0) jwt (>= 1.4, < 3.0) memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (~> 0.14) - grpc (1.28.0) - google-protobuf (~> 3.11) + grpc (1.38.0) + google-protobuf (~> 3.15) googleapis-common-protos-types (~> 1.0) - grpc-google-iam-v1 (0.6.10) - google-protobuf (~> 3.11) - googleapis-common-protos (>= 1.3.10, < 2.0) + grpc-google-iam-v1 (0.6.11) + google-protobuf (~> 3.14) + googleapis-common-protos (>= 1.3.11, < 2.0) grpc (~> 1.27) - i18n (1.8.3) + i18n (1.8.10) concurrent-ruby (~> 1.0) - jwt (2.2.1) + jwt (2.2.3) memoist (0.16.2) - minitest (5.14.1) - multi_json (1.14.1) + minitest (5.14.4) + multi_json (1.15.0) multipart-post (2.1.1) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) - os (1.1.0) - public_suffix (4.0.5) - raabro (1.3.1) + os (1.1.1) + public_suffix (4.0.6) + raabro (1.4.0) rack (2.2.3) - rack-protection (2.0.8.1) + rack-protection (2.1.0) rack - redis (4.2.1) + redis (4.2.5) retriable (3.1.2) rly (0.2.3) - ruby2_keywords (0.0.2) - signet (0.14.0) + ruby2_keywords (0.0.4) + signet (0.15.0) addressable (~> 2.3) faraday (>= 0.17.3, < 2.0) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - sinatra (2.0.8.1) + sinatra (2.1.0) mustermann (~> 1.0) - rack (~> 2.0) - rack-protection (= 2.0.8.1) + rack (~> 2.2) + rack-protection (= 2.1.0) tilt (~> 2.0) - thread_safe (0.3.6) tilt (2.0.10) - tzinfo (1.2.7) - thread_safe (~> 0.1) - zeitwerk (2.3.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + zeitwerk (2.4.2) PLATFORMS ruby @@ -105,7 +115,7 @@ DEPENDENCIES sinatra RUBY VERSION - ruby 2.5.5p157 + ruby 3.0.0p0 BUNDLED WITH - 2.1.4 + 2.2.3 diff --git a/gemfiles/rails_6.1.gemfile b/gemfiles/rails_6.1.gemfile new file mode 100644 index 00000000..184115e6 --- /dev/null +++ b/gemfiles/rails_6.1.gemfile @@ -0,0 +1,7 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "rails", "6.1" + +gemspec path: "../" diff --git a/lib/cloudtasker/backend/google_cloud_task.rb b/lib/cloudtasker/backend/google_cloud_task.rb index c02d60f8..0c04ef68 100644 --- a/lib/cloudtasker/backend/google_cloud_task.rb +++ b/lib/cloudtasker/backend/google_cloud_task.rb @@ -12,28 +12,30 @@ class GoogleCloudTask # # Create the queue configured in Cloudtasker if it does not already exist. # - # @param [String] queue_name The relative name of the queue. + # @param [String] :name The queue name + # @param [Integer] :concurrency The queue concurrency + # @param [Integer] :retries The number of retries for the queue # # @return [Google::Cloud::Tasks::V2beta3::Queue] The queue # - def self.setup_queue(**opts) + def self.setup_queue(name: nil, concurrency: nil, retries: nil) # Build full queue path - queue_name = opts[:name] || Cloudtasker::Config::DEFAULT_JOB_QUEUE + queue_name = name || Cloudtasker::Config::DEFAULT_JOB_QUEUE full_queue_name = queue_path(queue_name) # Try to get existing queue client.get_queue(full_queue_name) rescue Google::Gax::RetryError # Extract options - concurrency = (opts[:concurrency] || Cloudtasker::Config::DEFAULT_QUEUE_CONCURRENCY).to_i - retries = (opts[:retries] || Cloudtasker::Config::DEFAULT_QUEUE_RETRIES).to_i + queue_concurrency = (concurrency || Cloudtasker::Config::DEFAULT_QUEUE_CONCURRENCY).to_i + queue_retries = (retries || Cloudtasker::Config::DEFAULT_QUEUE_RETRIES).to_i # Create queue on 'not found' error client.create_queue( client.location_path(config.gcp_project_id, config.gcp_location_id), name: full_queue_name, - retry_config: { max_attempts: retries }, - rate_limits: { max_concurrent_dispatches: concurrency } + retry_config: { max_attempts: queue_retries }, + rate_limits: { max_concurrent_dispatches: queue_concurrency } ) end diff --git a/lib/cloudtasker/backend/memory_task.rb b/lib/cloudtasker/backend/memory_task.rb index b8804cab..31b49f34 100644 --- a/lib/cloudtasker/backend/memory_task.rb +++ b/lib/cloudtasker/backend/memory_task.rb @@ -62,7 +62,7 @@ def self.create(payload) payload = payload.merge(schedule_time: payload[:schedule_time].to_i) # Save task - task = new(payload.merge(id: id)) + task = new(**payload.merge(id: id)) queue << task # Execute task immediately if in testing and inline mode enabled diff --git a/lib/cloudtasker/backend/redis_task.rb b/lib/cloudtasker/backend/redis_task.rb index d89cecdf..8472cc48 100644 --- a/lib/cloudtasker/backend/redis_task.rb +++ b/lib/cloudtasker/backend/redis_task.rb @@ -89,7 +89,7 @@ def self.create(payload) # Save job redis.write(key(id), payload) redis.sadd(key, id) - new(payload.merge(id: id)) + new(**payload.merge(id: id)) end # @@ -103,7 +103,7 @@ def self.find(id) gid = key(id) return nil unless (payload = redis.fetch(gid)) - new(payload.merge(id: id)) + new(**payload.merge(id: id)) end # @@ -172,8 +172,12 @@ def gid # Retry the task later. # # @param [Integer] interval The delay in seconds before retrying the task + # @param [Hash] opts Additional options + # @option opts [Boolean] :is_error Increase number of retries. Default to true. # - def retry_later(interval, is_error: true) + def retry_later(interval, opts = {}) + is_error = opts.to_h.fetch(:is_error, true) + redis.write( gid, retries: is_error ? retries + 1 : retries, diff --git a/lib/cloudtasker/cloud_task.rb b/lib/cloudtasker/cloud_task.rb index 43928407..770e2023 100644 --- a/lib/cloudtasker/cloud_task.rb +++ b/lib/cloudtasker/cloud_task.rb @@ -37,7 +37,7 @@ def self.backend # def self.find(id) payload = backend.find(id)&.to_h - payload ? new(payload) : nil + payload ? new(**payload) : nil end # @@ -51,7 +51,7 @@ def self.create(payload) raise MaxTaskSizeExceededError if payload.to_json.bytesize > Config::MAX_TASK_SIZE resp = backend.create(payload)&.to_h - resp ? new(resp) : nil + resp ? new(**resp) : nil end # diff --git a/lib/cloudtasker/cron/schedule.rb b/lib/cloudtasker/cron/schedule.rb index 55f12837..0fed533a 100644 --- a/lib/cloudtasker/cron/schedule.rb +++ b/lib/cloudtasker/cron/schedule.rb @@ -93,7 +93,7 @@ def self.create(**opts) def self.find(id) return nil unless (schedule_config = redis.fetch(key(id))) - new(schedule_config) + new(**schedule_config) end # @@ -251,9 +251,9 @@ def next_time(*args) # # Buld edit the object attributes. # - # @param [Hash] **opts The attributes to edit. + # @param [Hash] opts The attributes to edit. # - def assign_attributes(**opts) + def assign_attributes(opts) opts .select { |k, _| instance_variables.include?("@#{k}".to_sym) } .each { |k, v| instance_variable_set("@#{k}", v) } @@ -262,9 +262,9 @@ def assign_attributes(**opts) # # Edit the object attributes and save the object in Redis. # - # @param [Hash] **opts The attributes to edit. + # @param [Hash] opts The attributes to edit. # - def update(**opts) + def update(opts) assign_attributes(opts) save end diff --git a/lib/cloudtasker/redis_client.rb b/lib/cloudtasker/redis_client.rb index 5775d006..aeb9d1c1 100644 --- a/lib/cloudtasker/redis_client.rb +++ b/lib/cloudtasker/redis_client.rb @@ -132,22 +132,47 @@ def search(pattern) list end - # - # Delegate all methods to the redis client. - # - # @param [String, Symbol] name The method to delegate. - # @param [Array] *args The list of method arguments. - # @param [Proc] &block Block passed to the method. - # - # @return [Any] The method return value - # - def method_missing(name, *args, &block) - if Redis.method_defined?(name) - client.with { |c| c.send(name, *args, &block) } - else - super + # rubocop:disable Style/MissingRespondToMissing + if RUBY_VERSION < '3' + # + # Delegate all methods to the redis client. + # Old delegation method. + # + # @param [String, Symbol] name The method to delegate. + # @param [Array] *args The list of method positional arguments. + # @param [Hash] *kwargs The list of method keyword arguments. + # @param [Proc] &block Block passed to the method. + # + # @return [Any] The method return value + # + def method_missing(name, *args, &block) + if Redis.method_defined?(name) + client.with { |c| c.send(name, *args, &block) } + else + super + end + end + else + # + # Delegate all methods to the redis client. + # Ruby 3 delegation method style. + # + # @param [String, Symbol] name The method to delegate. + # @param [Array] *args The list of method positional arguments. + # @param [Hash] *kwargs The list of method keyword arguments. + # @param [Proc] &block Block passed to the method. + # + # @return [Any] The method return value + # + def method_missing(name, *args, **kwargs, &block) + if Redis.method_defined?(name) + client.with { |c| c.send(name, *args, **kwargs, &block) } + else + super + end end end + # rubocop:enable Style/MissingRespondToMissing # # Check if the class respond to a certain method. diff --git a/lib/cloudtasker/unique_job/job.rb b/lib/cloudtasker/unique_job/job.rb index 19d7b8fe..df636b5b 100644 --- a/lib/cloudtasker/unique_job/job.rb +++ b/lib/cloudtasker/unique_job/job.rb @@ -14,10 +14,11 @@ class Job # Build a new instance of the class. # # @param [Cloudtasker::Worker] worker The worker at hand + # @param [Hash] worker The worker options # - def initialize(worker, **kwargs) + def initialize(worker, opts = {}) @worker = worker - @call_opts = kwargs + @call_opts = opts end # diff --git a/lib/cloudtasker/unique_job/middleware/client.rb b/lib/cloudtasker/unique_job/middleware/client.rb index 419b0da9..a52c8b93 100644 --- a/lib/cloudtasker/unique_job/middleware/client.rb +++ b/lib/cloudtasker/unique_job/middleware/client.rb @@ -3,9 +3,10 @@ module Cloudtasker module UniqueJob module Middleware + # TODO: kwargs to job otherwise it won't get the time_at # Client middleware, invoked when jobs are scheduled class Client - def call(worker, **_kwargs) + def call(worker, _opts = {}) Job.new(worker).lock_instance.schedule { yield } end end diff --git a/lib/cloudtasker/worker.rb b/lib/cloudtasker/worker.rb index 24ee7df3..b18e0044 100644 --- a/lib/cloudtasker/worker.rb +++ b/lib/cloudtasker/worker.rb @@ -47,7 +47,7 @@ def self.from_hash(hash) return nil unless worker_klass.include?(self) # Return instantiated worker - worker_klass.new(payload.slice(:job_queue, :job_args, :job_id, :job_meta, :job_retries, :task_id)) + worker_klass.new(**payload.slice(:job_queue, :job_args, :job_id, :job_meta, :job_retries, :task_id)) rescue NameError nil end @@ -121,7 +121,7 @@ def perform_at(time_at, *args) # @return [Cloudtasker::CloudTask] The Google Task response # def schedule(args: nil, time_in: nil, time_at: nil, queue: nil) - new(job_args: args, job_queue: queue).schedule({ interval: time_in, time_at: time_at }.compact) + new(job_args: args, job_queue: queue).schedule(**{ interval: time_in, time_at: time_at }.compact) end # @@ -239,7 +239,7 @@ def schedule_time(interval: nil, time_at: nil) # def schedule(**args) # Evaluate when to schedule the job - time_at = schedule_time(args) + time_at = schedule_time(**args) # Schedule job through client middlewares Cloudtasker.config.client_middleware.invoke(self, time_at: time_at) do diff --git a/lib/cloudtasker/worker_wrapper.rb b/lib/cloudtasker/worker_wrapper.rb index 82548e1c..61f874ed 100644 --- a/lib/cloudtasker/worker_wrapper.rb +++ b/lib/cloudtasker/worker_wrapper.rb @@ -27,7 +27,7 @@ class WorkerWrapper # def initialize(worker_name:, **opts) @worker_name = worker_name - super(opts) + super(**opts) end # diff --git a/spec/active_job/queue_adapters/cloudtasker_adapter/job_wrapper_spec.rb b/spec/active_job/queue_adapters/cloudtasker_adapter/job_wrapper_spec.rb index f47efce7..98dfcd1e 100644 --- a/spec/active_job/queue_adapters/cloudtasker_adapter/job_wrapper_spec.rb +++ b/spec/active_job/queue_adapters/cloudtasker_adapter/job_wrapper_spec.rb @@ -6,7 +6,7 @@ include_context 'of Cloudtasker ActiveJob instantiation' subject :worker do - described_class.new(example_job_wrapper_args.merge(task_id: '00000001')) + described_class.new(**example_job_wrapper_args.merge(task_id: '00000001')) end let :example_unreconstructed_job_serialization do diff --git a/spec/cloudtasker/backend/google_cloud_task_spec.rb b/spec/cloudtasker/backend/google_cloud_task_spec.rb index 2283d01d..c4071647 100644 --- a/spec/cloudtasker/backend/google_cloud_task_spec.rb +++ b/spec/cloudtasker/backend/google_cloud_task_spec.rb @@ -35,7 +35,7 @@ let(:client) { instance_double('Google::Cloud::Tasks::V2beta3::Task') } describe '.setup_queue' do - subject { described_class.setup_queue(opts) } + subject { described_class.setup_queue(**opts) } let(:opts) { { name: relative_queue, concurrency: 20, retries: 100 } } let(:queue) { instance_double('Google::Cloud::Tasks::V2beta3::Queue') } diff --git a/spec/cloudtasker/backend/memory_task_spec.rb b/spec/cloudtasker/backend/memory_task_spec.rb index 22d4c8ba..0330c2e7 100644 --- a/spec/cloudtasker/backend/memory_task_spec.rb +++ b/spec/cloudtasker/backend/memory_task_spec.rb @@ -41,9 +41,9 @@ let(:worker_name) { 'TestWorker' } let(:worker_name2) { 'TestWorker2' } let(:task_id) { '1234' } - let(:task) { described_class.new(job_payload.merge(id: task_id)) } + let(:task) { described_class.new(**job_payload.merge(id: task_id)) } let(:task_id2) { '2434' } - let(:task2) { described_class.new(job_payload2.merge(id: task_id2)) } + let(:task2) { described_class.new(**job_payload2.merge(id: task_id2)) } before { described_class.clear } @@ -160,7 +160,7 @@ end describe '.new' do - subject { described_class.new(job_payload.merge(id: id)) } + subject { described_class.new(**job_payload.merge(id: id)) } let(:id) { '123' } let(:expected_attrs) do @@ -251,11 +251,11 @@ subject { task } context 'with same id' do - it { is_expected.to eq(described_class.new(job_payload.merge(id: task_id))) } + it { is_expected.to eq(described_class.new(**job_payload.merge(id: task_id))) } end context 'with different id' do - it { is_expected.not_to eq(described_class.new(job_payload.merge(id: task_id + 'a'))) } + it { is_expected.not_to eq(described_class.new(**job_payload.merge(id: task_id + 'a'))) } end context 'with different object' do diff --git a/spec/cloudtasker/backend/redis_task_spec.rb b/spec/cloudtasker/backend/redis_task_spec.rb index b64600be..ba469c2e 100644 --- a/spec/cloudtasker/backend/redis_task_spec.rb +++ b/spec/cloudtasker/backend/redis_task_spec.rb @@ -22,7 +22,7 @@ } end let(:task_id) { '1234' } - let(:task) { described_class.new(job_payload.merge(id: task_id)) } + let(:task) { described_class.new(**job_payload.merge(id: task_id)) } describe '.redis' do subject { described_class.redis } @@ -69,9 +69,9 @@ let(:queue) { nil } let(:tasks) do [ - described_class.new(job_payload.merge(id: 1, queue: 'critical')), - described_class.new(job_payload.merge(id: 2, queue: 'default')), - described_class.new(job_payload.merge(id: 3, schedule_time: Time.now + 3600)) + described_class.new(**job_payload.merge(id: 1, queue: 'critical')), + described_class.new(**job_payload.merge(id: 2, queue: 'default')), + described_class.new(**job_payload.merge(id: 3, schedule_time: Time.now + 3600)) ] end @@ -94,8 +94,8 @@ let(:queue) { 'some-queue' } let(:tasks) do [ - described_class.new(job_payload.merge(id: 1)), - described_class.new(job_payload.merge(id: 2)) + described_class.new(**job_payload.merge(id: 1)), + described_class.new(**job_payload.merge(id: 2)) ] end @@ -124,7 +124,7 @@ describe '.find' do subject { described_class.find(task_id) } - let(:expected_record) { described_class.new(job_payload.merge(id: task_id)) } + let(:expected_record) { described_class.new(**job_payload.merge(id: task_id)) } context 'with record found' do before { allow(SecureRandom).to receive(:uuid).and_return(task_id) } @@ -153,7 +153,7 @@ end describe '.new' do - subject { described_class.new(args) } + subject { described_class.new(**args) } let(:id) { '123' } let(:args) { job_payload.merge(id: id) } @@ -279,11 +279,11 @@ subject { task } context 'with same id' do - it { is_expected.to eq(described_class.new(job_payload.merge(id: task_id))) } + it { is_expected.to eq(described_class.new(**job_payload.merge(id: task_id))) } end context 'with different id' do - it { is_expected.not_to eq(described_class.new(job_payload.merge(id: task_id + 'a'))) } + it { is_expected.not_to eq(described_class.new(**job_payload.merge(id: task_id + 'a'))) } end context 'with different object' do diff --git a/spec/cloudtasker/cloud_task_spec.rb b/spec/cloudtasker/cloud_task_spec.rb index 63c1f55d..efab4264 100644 --- a/spec/cloudtasker/cloud_task_spec.rb +++ b/spec/cloudtasker/cloud_task_spec.rb @@ -46,7 +46,7 @@ before { allow(backend).to receive(:find).with(id).and_return(call_resp) } context 'with response' do - it { is_expected.to eq(described_class.new(payload)) } + it { is_expected.to eq(described_class.new(**payload)) } end context 'with no response' do @@ -65,7 +65,7 @@ before { allow(backend).to receive(:create).with(payload).and_return(call_resp) } context 'with response' do - it { is_expected.to eq(described_class.new(payload)) } + it { is_expected.to eq(described_class.new(**payload)) } end context 'with no response' do @@ -93,20 +93,20 @@ end describe '.new' do - subject { described_class.new(payload) } + subject { described_class.new(**payload) } it { is_expected.to have_attributes(payload) } end describe '#==' do - subject { described_class.new(payload) } + subject { described_class.new(**payload) } context 'with same id' do - it { is_expected.to eq(described_class.new(payload)) } + it { is_expected.to eq(described_class.new(**payload)) } end context 'with different id' do - it { is_expected.not_to eq(described_class.new(payload.merge(id: payload[:id] + 'a'))) } + it { is_expected.not_to eq(described_class.new(**payload.merge(id: payload[:id] + 'a'))) } end context 'with different object' do diff --git a/spec/cloudtasker/cron/schedule_spec.rb b/spec/cloudtasker/cron/schedule_spec.rb index 6227eff0..c824b6f6 100644 --- a/spec/cloudtasker/cron/schedule_spec.rb +++ b/spec/cloudtasker/cron/schedule_spec.rb @@ -149,7 +149,7 @@ end describe '.new' do - subject { described_class.new(attrs) } + subject { described_class.new(**attrs) } let(:attrs) do { diff --git a/spec/cloudtasker/worker_spec.rb b/spec/cloudtasker/worker_spec.rb index 0332f921..fe39a927 100644 --- a/spec/cloudtasker/worker_spec.rb +++ b/spec/cloudtasker/worker_spec.rb @@ -118,7 +118,7 @@ end describe '.schedule' do - subject { worker_class.schedule(opts) } + subject { worker_class.schedule(**opts) } let(:queue) { 'some-queue' } let(:delay) { 10 } @@ -178,7 +178,7 @@ end describe '.new' do - subject { worker_class.new(worker_args) } + subject { worker_class.new(**worker_args) } let(:task_id) { SecureRandom.uuid } let(:id) { SecureRandom.uuid } diff --git a/spec/cloudtasker/worker_wrapper_spec.rb b/spec/cloudtasker/worker_wrapper_spec.rb index ad4d9c43..d7e7dbbd 100644 --- a/spec/cloudtasker/worker_wrapper_spec.rb +++ b/spec/cloudtasker/worker_wrapper_spec.rb @@ -12,7 +12,7 @@ end describe '.new' do - subject { described_class.new(worker_args.merge(worker_name: worker_class)) } + subject { described_class.new(**worker_args.merge(worker_name: worker_class)) } let(:id) { SecureRandom.uuid } let(:args) { [1, 2] } @@ -47,7 +47,7 @@ let(:job_meta) { { foo: 'bar' } } let(:job_queue) { 'critical' } let(:attrs) { { worker_name: worker_class, job_queue: job_queue, job_args: job_args, job_meta: job_meta } } - let(:worker) { described_class.new(attrs) } + let(:worker) { described_class.new(**attrs) } it { is_expected.to have_attributes(attrs.merge(job_meta: eq(job_meta))) } it { expect(new_instance.job_id).not_to eq(worker.job_id) } diff --git a/spec/support/test_middleware.rb b/spec/support/test_middleware.rb index 5db0175b..f941d125 100644 --- a/spec/support/test_middleware.rb +++ b/spec/support/test_middleware.rb @@ -7,10 +7,10 @@ def initialize(arg = nil) @arg = arg end - def call(worker, **kwargs) + def call(worker, opts = {}) @called = true worker.middleware_called = true if worker.respond_to?(:middleware_called) - worker.middleware_opts = kwargs if worker.respond_to?(:middleware_opts) + worker.middleware_opts = opts if worker.respond_to?(:middleware_opts) yield end end