cloudtasker 0.13.2 → 0.14.rc1

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint_rubocop.yml +1 -1
  3. data/.github/workflows/test_ruby_3.x.yml +1 -0
  4. data/.gitignore +4 -1
  5. data/.rubocop.yml +37 -9
  6. data/Appraisals +0 -12
  7. data/CHANGELOG.md +24 -0
  8. data/Gemfile +12 -0
  9. data/README.md +145 -6
  10. data/app/controllers/cloudtasker/worker_controller.rb +30 -9
  11. data/cloudtasker.gemspec +3 -10
  12. data/docs/CRON_JOBS.md +23 -0
  13. data/docs/STORABLE_JOBS.md +68 -0
  14. data/exe/cloudtasker +5 -2
  15. data/gemfiles/google_cloud_tasks_1.0.gemfile +10 -1
  16. data/gemfiles/google_cloud_tasks_1.1.gemfile +10 -1
  17. data/gemfiles/google_cloud_tasks_1.2.gemfile +10 -1
  18. data/gemfiles/google_cloud_tasks_1.3.gemfile +10 -1
  19. data/gemfiles/google_cloud_tasks_1.4.gemfile +10 -1
  20. data/gemfiles/google_cloud_tasks_1.5.gemfile +10 -1
  21. data/gemfiles/google_cloud_tasks_2.0.gemfile +10 -1
  22. data/gemfiles/google_cloud_tasks_2.1.gemfile +10 -1
  23. data/gemfiles/rails_5.2.gemfile +10 -0
  24. data/gemfiles/rails_6.0.gemfile +10 -0
  25. data/gemfiles/rails_6.1.gemfile +10 -0
  26. data/gemfiles/rails_7.0.gemfile +10 -0
  27. data/gemfiles/semantic_logger_3.4.gemfile +9 -1
  28. data/gemfiles/semantic_logger_4.6.gemfile +9 -1
  29. data/gemfiles/semantic_logger_4.7.0.gemfile +9 -1
  30. data/gemfiles/semantic_logger_4.7.2.gemfile +9 -1
  31. data/lib/active_job/queue_adapters/cloudtasker_adapter.rb +8 -1
  32. data/lib/cloudtasker/authenticator.rb +35 -0
  33. data/lib/cloudtasker/backend/google_cloud_task_v1.rb +2 -4
  34. data/lib/cloudtasker/backend/google_cloud_task_v2.rb +3 -5
  35. data/lib/cloudtasker/backend/memory_task.rb +1 -1
  36. data/lib/cloudtasker/backend/redis_task.rb +10 -4
  37. data/lib/cloudtasker/batch/batch_progress.rb +18 -14
  38. data/lib/cloudtasker/batch/job.rb +124 -31
  39. data/lib/cloudtasker/batch/middleware/server.rb +2 -2
  40. data/lib/cloudtasker/cli.rb +5 -7
  41. data/lib/cloudtasker/cloud_task.rb +16 -20
  42. data/lib/cloudtasker/config.rb +43 -10
  43. data/lib/cloudtasker/cron/middleware/server.rb +2 -2
  44. data/lib/cloudtasker/cron/schedule.rb +5 -2
  45. data/lib/cloudtasker/middleware/chain.rb +1 -1
  46. data/lib/cloudtasker/redis_client.rb +1 -4
  47. data/lib/cloudtasker/retry_worker_error.rb +6 -0
  48. data/lib/cloudtasker/storable/worker.rb +78 -0
  49. data/lib/cloudtasker/storable.rb +3 -0
  50. data/lib/cloudtasker/unique_job/conflict_strategy/base_strategy.rb +4 -2
  51. data/lib/cloudtasker/unique_job/lock/until_executed.rb +4 -4
  52. data/lib/cloudtasker/unique_job/lock/until_executing.rb +2 -2
  53. data/lib/cloudtasker/unique_job/lock/while_executing.rb +2 -2
  54. data/lib/cloudtasker/unique_job/middleware/client.rb +2 -2
  55. data/lib/cloudtasker/unique_job/middleware/server.rb +2 -2
  56. data/lib/cloudtasker/version.rb +1 -1
  57. data/lib/cloudtasker/worker.rb +38 -15
  58. data/lib/cloudtasker/worker_handler.rb +25 -19
  59. data/lib/cloudtasker/worker_logger.rb +48 -0
  60. data/lib/cloudtasker.rb +4 -1
  61. data/lib/tasks/setup_queue.rake +6 -6
  62. metadata +9 -145
  63. data/.github/workflows/test_ruby_2.6.yml +0 -37
@@ -0,0 +1,68 @@
1
+ # Cloudtasker Storable Jobs
2
+
3
+ **Supported since**: `v0.14.rc1`
4
+ **Note**: this extension requires redis
5
+
6
+ The Cloudtasker storage extension allows you to park jobs in a specific garage lane and enqueue (pull) them when specific conditions have been met.
7
+
8
+ This extension is useful when you need to prepare some jobs (e.g. you are retrieving data from an API and must process some of it asynchronously) but only process them when some programmatic conditions have been met (e.g. a series of preliminary preparation jobs have run successfully). Using parked jobs is a leaner (and cheaper) approach than using guard logic in the `perform` method to re-enqueue a job until a set of conditions is satisfied. The latter tends to generate a lot of jobs/logs pollution.
9
+
10
+ ## Configuration
11
+
12
+ You can enable storable jobs by adding the following to your cloudtasker initializer:
13
+ ```ruby
14
+ # The storable extension is optional and must be explicitly required
15
+ require 'cloudtasker/storable'
16
+
17
+ Cloudtasker.configure do |config|
18
+ # Specify your redis url.
19
+ # Defaults to `redis://localhost:6379/0` if unspecified
20
+ config.redis = { url: 'redis://some-host:6379/0' }
21
+ end
22
+ ```
23
+
24
+ Then you can make workers storable by including the `Cloudtasker::Storable::Worker` concern into your workers:
25
+ ```ruby
26
+ class MyWorker
27
+ include Cloudtasker::Worker
28
+ include Cloudtasker::Storable::Worker
29
+
30
+ def perform(...)
31
+ # Do stuff
32
+ end
33
+ end
34
+ ```
35
+
36
+ ## Parking jobs
37
+ You can park jobs to a specific garage lane using the `push_to_store(store_name, *worker_args)` class method:
38
+ ```ruby
39
+ MyWorker.push_to_store('some-customer-reference:some-task-group', job_arg1, job_arg2)
40
+ ```
41
+
42
+ ## Pulling jobs
43
+ You can pull and enqueue jobs using the `pull_all_from_store(store_name)` class method:
44
+ ```ruby
45
+ MyWorker.pull_all_from_store('some-customer-reference:some-task-group')
46
+ ```
47
+
48
+ If you need to enqueue jobs with specific options or using any special means, you can call `pull_all_from_store(store_name)` with a block. When a block is passed the method yield each worker's set of arguments.
49
+ ```ruby
50
+ # Delay the enqueuing of parked jobs by 30 seconds
51
+ MyWorker.pull_all_from_store('some-customer-reference:some-task-group') do |args|
52
+ MyWorker.perform_in(30, *args)
53
+ end
54
+
55
+ # Enqueue parked jobs on a specific queue, with a 10s delay
56
+ MyWorker.pull_all_from_store('some-customer-reference:some-task-group') do |args|
57
+ MyWorker.schedule(args: args, time_in: 10, queue: 'critical')
58
+ end
59
+
60
+ # Enqueue parked jobs as part of a job's current batch (the logic below assumes
61
+ # we are inside a job's `perform` method)
62
+ MyWorker.pull_all_from_store('some-customer-reference:some-task-group') do |args|
63
+ batch.add(MyWorker, *args)
64
+
65
+ # Or with a specific queue
66
+ # batch.add_to_queue('critical', SubWorker, *args)
67
+ end
68
+ ```
data/exe/cloudtasker CHANGED
@@ -9,8 +9,11 @@ options = {}
9
9
  OptionParser.new do |opts|
10
10
  opts.banner = 'Usage: cloudtasker [options]'
11
11
 
12
- opts.on('-q QUEUE', '--queue=QUEUE', 'Queue to process and number of threads. ' \
13
- "Examples: '-q critical' | '-q critical,2' | '-q critical,3 -q defaults,2'") do |o|
12
+ opts.on(
13
+ '-q QUEUE', '--queue=QUEUE',
14
+ 'Queue to process and number of threads. ' \
15
+ "Examples: '-q critical' | '-q critical,2' | '-q critical,3 -q defaults,2'"
16
+ ) do |o|
14
17
  options[:queues] ||= []
15
18
  options[:queues] << o.split(',')
16
19
  end
@@ -2,7 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
6
15
  gem "google-cloud-tasks", "~> 1.0.0"
7
16
 
8
17
  gemspec path: "../"
@@ -2,7 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
6
15
  gem "google-cloud-tasks", "~> 1.1.0"
7
16
 
8
17
  gemspec path: "../"
@@ -2,7 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
6
15
  gem "google-cloud-tasks", "~> 1.2.0"
7
16
 
8
17
  gemspec path: "../"
@@ -2,7 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
6
15
  gem "google-cloud-tasks", "~> 1.3.0"
7
16
 
8
17
  gemspec path: "../"
@@ -2,7 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
6
15
  gem "google-cloud-tasks", "~> 1.4.0"
7
16
 
8
17
  gemspec path: "../"
@@ -2,7 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
6
15
  gem "google-cloud-tasks", "~> 1.5.0"
7
16
 
8
17
  gemspec path: "../"
@@ -2,7 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
6
15
  gem "google-cloud-tasks", "~> 2.0.0"
7
16
 
8
17
  gemspec path: "../"
@@ -2,7 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
6
15
  gem "google-cloud-tasks", "~> 2.1.0"
7
16
 
8
17
  gemspec path: "../"
@@ -2,6 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
5
15
  gem "rails", "~> 5.2.0"
6
16
  gem "rspec-rails"
7
17
 
@@ -2,6 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
5
15
  gem "rails", "~> 6.0.0"
6
16
  gem "rspec-rails"
7
17
 
@@ -2,6 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
5
15
  gem "rails", "~> 6.1.0"
6
16
  gem "rspec-rails"
7
17
 
@@ -2,6 +2,16 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
12
+ gem "semantic_logger"
13
+ gem "timecop"
14
+ gem "webmock"
5
15
  gem "rails", "~> 7.0.0"
6
16
  gem "rspec-rails"
7
17
 
@@ -2,7 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
6
12
  gem "semantic_logger", "3.4.1"
13
+ gem "timecop"
14
+ gem "webmock"
7
15
 
8
16
  gemspec path: "../"
@@ -2,7 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
6
12
  gem "semantic_logger", "4.6.1"
13
+ gem "timecop"
14
+ gem "webmock"
7
15
 
8
16
  gemspec path: "../"
@@ -2,7 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
6
12
  gem "semantic_logger", "4.7.0"
13
+ gem "timecop"
14
+ gem "webmock"
7
15
 
8
16
  gemspec path: "../"
@@ -2,7 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activesupport", "~> 6.1.0"
5
+ gem "appraisal", github: "thoughtbot/appraisal"
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", ">= 12.3.3"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-json_expectations", "~> 2.2"
10
+ gem "rubocop", "~> 1.64.1"
11
+ gem "rubocop-rspec", "~> 3.0.1"
6
12
  gem "semantic_logger", "4.7.2"
13
+ gem "timecop"
14
+ gem "webmock"
7
15
 
8
16
  gemspec path: "../"
@@ -38,6 +38,13 @@ module ActiveJob
38
38
  build_worker(job).schedule(time_at: Time.at(precise_timestamp))
39
39
  end
40
40
 
41
+ # Determines if enqueuing will check and wait for an associated transaction completes before enqueuing
42
+ #
43
+ # @return [Boolean] True always as this is the default from QueueAdapters::AbstractAdapter
44
+ def enqueue_after_transaction_commit?
45
+ true
46
+ end
47
+
41
48
  private
42
49
 
43
50
  def build_worker(job)
@@ -53,7 +60,7 @@ module ActiveJob
53
60
  # == Job Wrapper for the Cloudtasker adapter
54
61
  #
55
62
  # Executes jobs scheduled by the Cloudtasker ActiveJob adapter
56
- class JobWrapper #:nodoc:
63
+ class JobWrapper # :nodoc:
57
64
  include Cloudtasker::Worker
58
65
 
59
66
  # Executes the given serialized ActiveJob call.
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'openssl'
4
+
3
5
  module Cloudtasker
4
6
  # Manage token generation and verification
5
7
  module Authenticator
@@ -27,6 +29,15 @@ module Cloudtasker
27
29
  JWT.encode({ iat: Time.now.to_i }, config.secret, JWT_ALG)
28
30
  end
29
31
 
32
+ #
33
+ # The Authorization header content
34
+ #
35
+ # @return [String] The Bearer authorization header
36
+ #
37
+ def bearer_token
38
+ "Bearer #{verification_token}"
39
+ end
40
+
30
41
  #
31
42
  # Verify a bearer token (jwt token)
32
43
  #
@@ -51,5 +62,29 @@ module Cloudtasker
51
62
  def verify!(bearer_token)
52
63
  verify(bearer_token) || raise(AuthenticationError)
53
64
  end
65
+
66
+ #
67
+ # Generate a signature for a payload
68
+ #
69
+ # @param [String] payload The JSON payload
70
+ #
71
+ # @return [String] The HMAC signature
72
+ #
73
+ def sign_payload(payload)
74
+ OpenSSL::HMAC.hexdigest('sha256', config.secret, payload)
75
+ end
76
+
77
+ #
78
+ # Verify that a signature matches the payload and raise a `Cloudtasker::AuthenticationError`
79
+ # if the signature is invalid.
80
+ #
81
+ # @param [String] signature The tested signature
82
+ # @param [String] payload The JSON payload
83
+ #
84
+ # @return [Boolean] Return true if the signature is valid
85
+ #
86
+ def verify_signature!(signature, payload)
87
+ ActiveSupport::SecurityUtils.secure_compare(signature, sign_payload(payload)) || raise(AuthenticationError)
88
+ end
54
89
  end
55
90
  end
@@ -177,10 +177,8 @@ module Cloudtasker
177
177
  #
178
178
  # Helper method encapsulating the retry strategy for GAX calls
179
179
  #
180
- def self.with_gax_retries
181
- Retriable.retriable(on: [Google::Gax::UnavailableError], tries: 3) do
182
- yield
183
- end
180
+ def self.with_gax_retries(&block)
181
+ Retriable.retriable(on: [Google::Gax::UnavailableError], tries: 3, &block)
184
182
  end
185
183
 
186
184
  #
@@ -110,7 +110,7 @@ module Cloudtasker
110
110
  #
111
111
  # @param [Hash] hash The worker payload.
112
112
  #
113
- # @return [Hash] The Cloud Task payloadd.
113
+ # @return [Hash] The Cloud Task payload.
114
114
  #
115
115
  def self.format_task_payload(payload)
116
116
  payload = JSON.parse(payload.to_json, symbolize_names: true) # deep dup
@@ -180,10 +180,8 @@ module Cloudtasker
180
180
  #
181
181
  # Helper method encapsulating the retry strategy for Google API calls
182
182
  #
183
- def self.with_gapi_retries
184
- Retriable.retriable(on: [Google::Cloud::UnavailableError], tries: 3) do
185
- yield
186
- end
183
+ def self.with_gapi_retries(&block)
184
+ Retriable.retriable(on: [Google::Cloud::UnavailableError], tries: 3, &block)
187
185
  end
188
186
 
189
187
  #
@@ -131,7 +131,7 @@ module Cloudtasker
131
131
  # @return [Hash] The task payload.
132
132
  #
133
133
  def payload
134
- @payload ||= JSON.parse(http_request.dig(:body), symbolize_names: true)
134
+ @payload ||= JSON.parse(http_request[:body], symbolize_names: true)
135
135
  end
136
136
 
137
137
  #
@@ -12,9 +12,9 @@ module Cloudtasker
12
12
  RETRY_INTERVAL = 20 # seconds
13
13
 
14
14
  #
15
- # Return the cloudtasker redis client
15
+ # Return the Cloudtasker redis client
16
16
  #
17
- # @return [Cloudtasker::RedisClient] The cloudtasker redis client..
17
+ # @return [Cloudtasker::RedisClient] The cloudtasker redis client.
18
18
  #
19
19
  def self.redis
20
20
  @redis ||= RedisClient.new
@@ -52,7 +52,7 @@ module Cloudtasker
52
52
  end
53
53
 
54
54
  #
55
- # Reeturn all tasks ready to process.
55
+ # Return all tasks ready to process.
56
56
  #
57
57
  # @param [String] queue The queue to retrieve items from.
58
58
  #
@@ -215,6 +215,9 @@ module Cloudtasker
215
215
  end
216
216
 
217
217
  resp
218
+ rescue Errno::ECONNREFUSED
219
+ retry_later(RETRY_INTERVAL)
220
+ Cloudtasker.logger.info(format_log_message("Processor not ready - Retry in #{RETRY_INTERVAL} seconds..."))
218
221
  rescue Net::ReadTimeout
219
222
  retry_later(RETRY_INTERVAL)
220
223
  Cloudtasker.logger.info(
@@ -257,7 +260,10 @@ module Cloudtasker
257
260
  @http_client ||=
258
261
  begin
259
262
  uri = URI(http_request[:url])
260
- Net::HTTP.new(uri.host, uri.port).tap { |e| e.read_timeout = dispatch_deadline }
263
+ http = Net::HTTP.new(uri.host, uri.port).tap { |e| e.read_timeout = dispatch_deadline }
264
+ http.use_ssl = true if uri.instance_of?(URI::HTTPS)
265
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless Cloudtasker.config.local_server_ssl_verify
266
+ http
261
267
  end
262
268
  end
263
269
 
@@ -6,15 +6,28 @@ module Cloudtasker
6
6
  module Batch
7
7
  # Capture the progress of a batch
8
8
  class BatchProgress
9
- attr_reader :batch_state
9
+ attr_reader :batches
10
10
 
11
11
  #
12
12
  # Build a new instance of the class.
13
13
  #
14
- # @param [Hash] batch_state The batch state
14
+ # @param [Array<Cloudtasker::Batch::Job>] batches The batches to consider
15
15
  #
16
- def initialize(batch_state = {})
17
- @batch_state = batch_state
16
+ def initialize(batches = [])
17
+ @batches = batches
18
+ end
19
+
20
+ # Count the number of items in a given status
21
+
22
+ #
23
+ # Count the number of items in a given status
24
+ #
25
+ # @param [String] status The status to count
26
+ #
27
+ # @return [Integer] The number of jobs in the status
28
+ #
29
+ def count(status = 'all')
30
+ batches.sum { |e| e.batch_state_count(status) }
18
31
  end
19
32
 
20
33
  #
@@ -122,16 +135,7 @@ module Cloudtasker
122
135
  # @return [Cloudtasker::Batch::BatchProgress] The sum of the two batch progresses.
123
136
  #
124
137
  def +(other)
125
- self.class.new(batch_state.to_h.merge(other.batch_state.to_h))
126
- end
127
-
128
- private
129
-
130
- # Count the number of items in a given status
131
- def count(status = nil)
132
- return batch_state.to_h.keys.size unless status
133
-
134
- batch_state.to_h.values.count { |e| e == status }
138
+ self.class.new(batches + other.batches)
135
139
  end
136
140
  end
137
141
  end