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.
- checksums.yaml +4 -4
- data/.github/workflows/lint_rubocop.yml +1 -1
- data/.github/workflows/test_ruby_3.x.yml +1 -0
- data/.gitignore +4 -1
- data/.rubocop.yml +37 -9
- data/Appraisals +0 -12
- data/CHANGELOG.md +24 -0
- data/Gemfile +12 -0
- data/README.md +145 -6
- data/app/controllers/cloudtasker/worker_controller.rb +30 -9
- data/cloudtasker.gemspec +3 -10
- data/docs/CRON_JOBS.md +23 -0
- data/docs/STORABLE_JOBS.md +68 -0
- data/exe/cloudtasker +5 -2
- data/gemfiles/google_cloud_tasks_1.0.gemfile +10 -1
- data/gemfiles/google_cloud_tasks_1.1.gemfile +10 -1
- data/gemfiles/google_cloud_tasks_1.2.gemfile +10 -1
- data/gemfiles/google_cloud_tasks_1.3.gemfile +10 -1
- data/gemfiles/google_cloud_tasks_1.4.gemfile +10 -1
- data/gemfiles/google_cloud_tasks_1.5.gemfile +10 -1
- data/gemfiles/google_cloud_tasks_2.0.gemfile +10 -1
- data/gemfiles/google_cloud_tasks_2.1.gemfile +10 -1
- data/gemfiles/rails_5.2.gemfile +10 -0
- data/gemfiles/rails_6.0.gemfile +10 -0
- data/gemfiles/rails_6.1.gemfile +10 -0
- data/gemfiles/rails_7.0.gemfile +10 -0
- data/gemfiles/semantic_logger_3.4.gemfile +9 -1
- data/gemfiles/semantic_logger_4.6.gemfile +9 -1
- data/gemfiles/semantic_logger_4.7.0.gemfile +9 -1
- data/gemfiles/semantic_logger_4.7.2.gemfile +9 -1
- data/lib/active_job/queue_adapters/cloudtasker_adapter.rb +8 -1
- data/lib/cloudtasker/authenticator.rb +35 -0
- data/lib/cloudtasker/backend/google_cloud_task_v1.rb +2 -4
- data/lib/cloudtasker/backend/google_cloud_task_v2.rb +3 -5
- data/lib/cloudtasker/backend/memory_task.rb +1 -1
- data/lib/cloudtasker/backend/redis_task.rb +10 -4
- data/lib/cloudtasker/batch/batch_progress.rb +18 -14
- data/lib/cloudtasker/batch/job.rb +124 -31
- data/lib/cloudtasker/batch/middleware/server.rb +2 -2
- data/lib/cloudtasker/cli.rb +5 -7
- data/lib/cloudtasker/cloud_task.rb +16 -20
- data/lib/cloudtasker/config.rb +43 -10
- data/lib/cloudtasker/cron/middleware/server.rb +2 -2
- data/lib/cloudtasker/cron/schedule.rb +5 -2
- data/lib/cloudtasker/middleware/chain.rb +1 -1
- data/lib/cloudtasker/redis_client.rb +1 -4
- data/lib/cloudtasker/retry_worker_error.rb +6 -0
- data/lib/cloudtasker/storable/worker.rb +78 -0
- data/lib/cloudtasker/storable.rb +3 -0
- data/lib/cloudtasker/unique_job/conflict_strategy/base_strategy.rb +4 -2
- data/lib/cloudtasker/unique_job/lock/until_executed.rb +4 -4
- data/lib/cloudtasker/unique_job/lock/until_executing.rb +2 -2
- data/lib/cloudtasker/unique_job/lock/while_executing.rb +2 -2
- data/lib/cloudtasker/unique_job/middleware/client.rb +2 -2
- data/lib/cloudtasker/unique_job/middleware/server.rb +2 -2
- data/lib/cloudtasker/version.rb +1 -1
- data/lib/cloudtasker/worker.rb +38 -15
- data/lib/cloudtasker/worker_handler.rb +25 -19
- data/lib/cloudtasker/worker_logger.rb +48 -0
- data/lib/cloudtasker.rb +4 -1
- data/lib/tasks/setup_queue.rake +6 -6
- metadata +9 -145
- 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(
|
13
|
-
|
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 "
|
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 "
|
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 "
|
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 "
|
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 "
|
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 "
|
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 "
|
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 "
|
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: "../"
|
data/gemfiles/rails_5.2.gemfile
CHANGED
@@ -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
|
|
data/gemfiles/rails_6.0.gemfile
CHANGED
@@ -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
|
|
data/gemfiles/rails_6.1.gemfile
CHANGED
@@ -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
|
|
data/gemfiles/rails_7.0.gemfile
CHANGED
@@ -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 "
|
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 "
|
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 "
|
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 "
|
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
|
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)
|
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
|
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)
|
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
|
#
|
@@ -12,9 +12,9 @@ module Cloudtasker
|
|
12
12
|
RETRY_INTERVAL = 20 # seconds
|
13
13
|
|
14
14
|
#
|
15
|
-
# Return the
|
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
|
-
#
|
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 :
|
9
|
+
attr_reader :batches
|
10
10
|
|
11
11
|
#
|
12
12
|
# Build a new instance of the class.
|
13
13
|
#
|
14
|
-
# @param [
|
14
|
+
# @param [Array<Cloudtasker::Batch::Job>] batches The batches to consider
|
15
15
|
#
|
16
|
-
def initialize(
|
17
|
-
@
|
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(
|
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
|