cloudtasker 0.14.0 → 0.15.rc2
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 +19 -18
- data/.gitignore +1 -1
- data/.rubocop.yml +15 -12
- data/Appraisals +18 -20
- data/CHANGELOG.md +12 -1
- data/Gemfile +2 -2
- data/README.md +56 -0
- data/app/controllers/cloudtasker/worker_controller.rb +1 -1
- data/cloudtasker.gemspec +1 -1
- data/docs/UNIQUE_JOBS.md +1 -0
- data/gemfiles/google_cloud_tasks_1.0.gemfile +1 -1
- data/gemfiles/google_cloud_tasks_1.1.gemfile +1 -1
- data/gemfiles/google_cloud_tasks_1.2.gemfile +1 -1
- data/gemfiles/google_cloud_tasks_1.3.gemfile +1 -1
- data/gemfiles/google_cloud_tasks_1.4.gemfile +1 -1
- data/gemfiles/google_cloud_tasks_1.5.gemfile +1 -1
- data/gemfiles/google_cloud_tasks_2.0.gemfile +1 -1
- data/gemfiles/google_cloud_tasks_2.1.gemfile +1 -1
- data/gemfiles/rails_6.1.gemfile +3 -1
- data/gemfiles/rails_7.0.gemfile +1 -1
- data/gemfiles/rails_7.1.gemfile +1 -1
- data/gemfiles/{rails_5.2.gemfile → rails_8.0.gemfile} +2 -2
- data/gemfiles/{rails_6.0.gemfile → rails_8.1.gemfile} +2 -2
- data/gemfiles/semantic_logger_3.4.gemfile +1 -1
- data/gemfiles/semantic_logger_4.6.gemfile +1 -1
- data/gemfiles/semantic_logger_4.7.0.gemfile +1 -1
- data/gemfiles/semantic_logger_4.7.2.gemfile +1 -1
- data/lib/cloudtasker/backend/memory_task.rb +1 -1
- data/lib/cloudtasker/backend/redis_task.rb +3 -3
- data/lib/cloudtasker/config.rb +3 -0
- data/lib/cloudtasker/redis_client.rb +17 -37
- data/lib/cloudtasker/unique_job/lock/until_completed.rb +40 -0
- data/lib/cloudtasker/unique_job/middleware.rb +1 -0
- data/lib/cloudtasker/version.rb +1 -1
- data/lib/cloudtasker/worker.rb +27 -3
- data/lib/cloudtasker/worker_logger.rb +2 -2
- metadata +6 -6
- data/.github/workflows/test_ruby_2.7.yml +0 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 42cff7c50d99de1f66e83e04a3946c7cf370ce03004ee47dc7ee3dcbb46564c8
|
|
4
|
+
data.tar.gz: 26997c5f357a41563a074e2d03ea2724c3824b46a4b034e45b9e5573d4024cbe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0aa102da9cbc6ba0d108eb5d3be521efd954544bc7f4a47c11830401c61d2e590cbad7d7d540448dd4c41df7d11774c663c519a1b044518dc1a7c9f46c2c5906
|
|
7
|
+
data.tar.gz: b415391333360f336f0553297206ce725df0d617a14f3dc0a8fe8c8fb81b7ead8b9fbe92f608ba75214af0469161b2abf1aab65c9b400900a7e5b047d6ed4a18
|
|
@@ -8,25 +8,26 @@ jobs:
|
|
|
8
8
|
strategy:
|
|
9
9
|
matrix:
|
|
10
10
|
ruby:
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
11
|
+
- "3.0"
|
|
12
|
+
- "3.1"
|
|
13
|
+
- "3.2"
|
|
14
|
+
- "3.3"
|
|
15
|
+
- "3.4"
|
|
15
16
|
appraisal:
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
17
|
+
- "google_cloud_tasks_1.0"
|
|
18
|
+
- "google_cloud_tasks_1.1"
|
|
19
|
+
- "google_cloud_tasks_1.2"
|
|
20
|
+
- "google_cloud_tasks_1.3"
|
|
21
|
+
- "google_cloud_tasks_1.4"
|
|
22
|
+
- "google_cloud_tasks_1.5"
|
|
23
|
+
- "google_cloud_tasks_2.0"
|
|
24
|
+
- "google_cloud_tasks_2.1"
|
|
25
|
+
- "rails_6.1"
|
|
26
|
+
- "rails_7.0"
|
|
27
|
+
- "semantic_logger_3.4"
|
|
28
|
+
- "semantic_logger_4.6"
|
|
29
|
+
- "semantic_logger_4.7.0"
|
|
30
|
+
- "semantic_logger_4.7.2"
|
|
30
31
|
env:
|
|
31
32
|
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.appraisal }}.gemfile
|
|
32
33
|
steps:
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -3,10 +3,10 @@ require: rubocop-rspec
|
|
|
3
3
|
AllCops:
|
|
4
4
|
NewCops: enable
|
|
5
5
|
SuggestExtensions: false
|
|
6
|
-
TargetRubyVersion:
|
|
6
|
+
TargetRubyVersion: 3.0
|
|
7
7
|
Exclude:
|
|
8
|
-
-
|
|
9
|
-
-
|
|
8
|
+
- "gemfiles/**/*"
|
|
9
|
+
- "vendor/**/*"
|
|
10
10
|
|
|
11
11
|
Metrics/ClassLength:
|
|
12
12
|
Max: 300
|
|
@@ -17,7 +17,7 @@ Metrics/ModuleLength:
|
|
|
17
17
|
Metrics/AbcSize:
|
|
18
18
|
Max: 30
|
|
19
19
|
Exclude:
|
|
20
|
-
-
|
|
20
|
+
- "spec/support/*"
|
|
21
21
|
|
|
22
22
|
Metrics/PerceivedComplexity:
|
|
23
23
|
Max: 20
|
|
@@ -30,7 +30,7 @@ Metrics/MethodLength:
|
|
|
30
30
|
|
|
31
31
|
RSpec/DescribeClass:
|
|
32
32
|
Exclude:
|
|
33
|
-
-
|
|
33
|
+
- "spec/integration/**/*_spec.rb"
|
|
34
34
|
|
|
35
35
|
RSpec/ExpectInHook:
|
|
36
36
|
Enabled: false
|
|
@@ -44,12 +44,15 @@ RSpec/ScatteredSetup:
|
|
|
44
44
|
Metrics/BlockLength:
|
|
45
45
|
Exclude:
|
|
46
46
|
- cloudtasker.gemspec
|
|
47
|
-
-
|
|
47
|
+
- "spec/**/*"
|
|
48
48
|
|
|
49
49
|
Style/Documentation:
|
|
50
50
|
Exclude:
|
|
51
|
-
-
|
|
52
|
-
-
|
|
51
|
+
- "examples/**/*"
|
|
52
|
+
- "spec/**/*"
|
|
53
|
+
|
|
54
|
+
Style/SafeNavigationChainLength:
|
|
55
|
+
Enabled: false
|
|
53
56
|
|
|
54
57
|
Metrics/ParameterLists:
|
|
55
58
|
CountKeywordArgs: false
|
|
@@ -59,15 +62,15 @@ Metrics/CyclomaticComplexity:
|
|
|
59
62
|
|
|
60
63
|
Lint/EmptyBlock:
|
|
61
64
|
Exclude:
|
|
62
|
-
-
|
|
65
|
+
- "examples/rails/config/routes.rb"
|
|
63
66
|
|
|
64
67
|
RSpec/MessageSpies:
|
|
65
68
|
Enabled: false
|
|
66
69
|
|
|
67
70
|
RSpec/MultipleExpectations:
|
|
68
71
|
Exclude:
|
|
69
|
-
-
|
|
70
|
-
-
|
|
72
|
+
- "examples/**/*"
|
|
73
|
+
- "spec/integration/**/*"
|
|
71
74
|
|
|
72
75
|
RSpec/AnyInstance:
|
|
73
76
|
Enabled: false
|
|
@@ -90,4 +93,4 @@ RSpec/VerifiedDoubles:
|
|
|
90
93
|
Exclude:
|
|
91
94
|
- spec/cloudtasker/cloud_task_spec.rb
|
|
92
95
|
- spec/cloudtasker/backend/google_cloud_task_v1_spec.rb
|
|
93
|
-
- spec/cloudtasker/backend/google_cloud_task_v2_spec.rb
|
|
96
|
+
- spec/cloudtasker/backend/google_cloud_task_v2_spec.rb
|
data/Appraisals
CHANGED
|
@@ -32,33 +32,31 @@ appraise 'google_cloud_tasks_2.1' do
|
|
|
32
32
|
gem 'google-cloud-tasks', '~> 2.1.0'
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
appraise 'rails_6.1' do
|
|
36
|
+
gem 'rails', '~> 6.1.0'
|
|
37
|
+
gem 'rspec-rails'
|
|
38
|
+
gem 'mutex_m'
|
|
39
|
+
gem 'drb'
|
|
40
|
+
end
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
end
|
|
42
|
+
appraise 'rails_7.0' do
|
|
43
|
+
gem 'rails', '~> 7.0.0'
|
|
44
|
+
gem 'rspec-rails'
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
appraise '
|
|
48
|
-
gem 'rails', '~>
|
|
47
|
+
appraise 'rails_7.1' do
|
|
48
|
+
gem 'rails', '~> 7.1'
|
|
49
49
|
gem 'rspec-rails'
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
end
|
|
52
|
+
appraise 'rails_8.0' do
|
|
53
|
+
gem 'rails', '~> 8.0'
|
|
54
|
+
gem 'rspec-rails'
|
|
55
|
+
end
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
end
|
|
57
|
+
appraise 'rails_8.1' do
|
|
58
|
+
gem 'rails', '~> 8.1'
|
|
59
|
+
gem 'rspec-rails'
|
|
62
60
|
end
|
|
63
61
|
|
|
64
62
|
appraise 'semantic_logger_3.4' do
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v0.15.rc2](https://github.com/keypup-io/cloudtasker/tree/v0.15.rc2) (2025-11-13)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.14.0...v0.15.rc2)
|
|
6
|
+
|
|
7
|
+
**Improvements:**
|
|
8
|
+
- Queues: support `propagate_queue: true` option on `cloudtasker_options` to make workers enqueued inside a job use the runtime queue instead of the default (class-configured or `default`) queue.
|
|
9
|
+
- Unique Jobs: add `until_completed` strategy to lock jobs until they are completed or have exhausted all retries (thanks @jam-packed).
|
|
10
|
+
- Workers: provide `perform_now` method to perform job inline and align with other job frameworks
|
|
11
|
+
|
|
12
|
+
**Maintenance:**
|
|
13
|
+
- Supported rubies: drop support for ruby `2.7`. Cloudtasker now requires ruby `3.0` and above.
|
|
14
|
+
|
|
3
15
|
## [v0.14.0](https://github.com/keypup-io/cloudtasker/tree/v0.14.0) (2025-02-11)
|
|
4
16
|
|
|
5
17
|
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.13.2...v0.14.0)
|
|
@@ -23,7 +35,6 @@
|
|
|
23
35
|
- Rails: Use `skip_forgery_protection` instead of `skip_before_action`. The later was causing occasional issues on some setups.
|
|
24
36
|
|
|
25
37
|
|
|
26
|
-
|
|
27
38
|
## [v0.13.2](https://github.com/keypup-io/cloudtasker/tree/v0.13.2) (2023-07-02)
|
|
28
39
|
|
|
29
40
|
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.13.1...v0.13.2)
|
data/Gemfile
CHANGED
|
@@ -6,12 +6,12 @@ source 'https://rubygems.org'
|
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
8
|
# Dev dependencies
|
|
9
|
-
gem 'appraisal'
|
|
9
|
+
gem 'appraisal'
|
|
10
10
|
gem 'bundler', '~> 2.0'
|
|
11
11
|
gem 'rake', '>= 12.3.3'
|
|
12
12
|
gem 'rspec', '~> 3.0'
|
|
13
13
|
gem 'rspec-json_expectations', '~> 2.2'
|
|
14
|
-
gem 'rubocop', '~> 1.
|
|
14
|
+
gem 'rubocop', '~> 1.75.2'
|
|
15
15
|
gem 'rubocop-rspec', '~> 3.0.1'
|
|
16
16
|
gem 'semantic_logger'
|
|
17
17
|
gem 'timecop'
|
data/README.md
CHANGED
|
@@ -120,6 +120,10 @@ Open a Rails console and enqueue some jobs
|
|
|
120
120
|
|
|
121
121
|
# Process job in 60 seconds
|
|
122
122
|
DummyWorker.perform_in(60, 'foo')
|
|
123
|
+
|
|
124
|
+
# Process job immediately, inline
|
|
125
|
+
# Supported since: v0.15.rc2
|
|
126
|
+
DummyWorker.perform_now('foo')
|
|
123
127
|
```
|
|
124
128
|
|
|
125
129
|
Your Rails logs should display the following:
|
|
@@ -474,6 +478,11 @@ MyWorker.perform_at(3.days.from_now, arg1, arg2)
|
|
|
474
478
|
MyWorker.schedule(args: [arg1, arg2], time_at: Time.parse('2025-01-01 00:50:00Z'), queue: 'critical')
|
|
475
479
|
# or
|
|
476
480
|
MyWorker.schedule(args: [arg1, arg2], time_in: 5 * 60, queue: 'critical')
|
|
481
|
+
|
|
482
|
+
# Perform worker immediately, inline. This will not send the job to
|
|
483
|
+
# the processing queue. Middlewares such as Unique Job, Batch Jobs will still be invoked.
|
|
484
|
+
# Supported since: v0.15.rc2
|
|
485
|
+
MyWorker.perform_now(arg1, arg2)
|
|
477
486
|
```
|
|
478
487
|
|
|
479
488
|
Cloudtasker also provides a helper for re-enqueuing jobs. Re-enqueued jobs keep the same job id. Some middlewares may rely on this to track the fact that that a job didn't actually complete (e.g. Cloustasker batch). This is optional and you can always fallback to using exception management (raise an error) to retry/re-enqueue jobs.
|
|
@@ -545,6 +554,53 @@ Queues can also be assigned at runtime when scheduling a job:
|
|
|
545
554
|
CriticalWorker.schedule(args: [1], queue: :important)
|
|
546
555
|
```
|
|
547
556
|
|
|
557
|
+
### Propagating the queue in child workers
|
|
558
|
+
**Supported since:** `v0.15.rc2`
|
|
559
|
+
|
|
560
|
+
You can specify `propagate_queue: true` via the `cloudtasker_options` to make workers enqueued inside a job use the runtime queue instead of the default (class-configured or `default`) queue:
|
|
561
|
+
|
|
562
|
+
```ruby
|
|
563
|
+
# app/workers/child_worker.rb
|
|
564
|
+
|
|
565
|
+
class ChildWorker
|
|
566
|
+
include Cloudtasker::Worker
|
|
567
|
+
|
|
568
|
+
cloudtasker_options queue: :level2
|
|
569
|
+
|
|
570
|
+
def perform(some_arg)
|
|
571
|
+
logger.info("This is a child job, which is set to run on the level2 queue by default.")
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
```ruby
|
|
577
|
+
# app/workers/parent_worker.rb
|
|
578
|
+
|
|
579
|
+
class ParentWorker
|
|
580
|
+
include Cloudtasker::Worker
|
|
581
|
+
|
|
582
|
+
cloudtasker_options queue: :level1, propagate_queue: true
|
|
583
|
+
|
|
584
|
+
def perform(some_arg)
|
|
585
|
+
logger.info("This is a parent job, which is set to run on the level1 queue by default.")
|
|
586
|
+
|
|
587
|
+
# This worker will run on queue 'level1' instead of 'level2' because
|
|
588
|
+
# the "propagate_queue: true" has been specified on the parent.
|
|
589
|
+
ChildWorker.perform_async(some_arg)
|
|
590
|
+
|
|
591
|
+
# This worker will run on queue 'level3' because the queue has been explicitly
|
|
592
|
+
# specified on the scheduling options. It overrides the propagate_queue behaviour.
|
|
593
|
+
ChildWorker.schedule(queue: 'level3', args: [some_arg])
|
|
594
|
+
|
|
595
|
+
# This worker will run on queue 'level4' and the first ChildWorker it enqueues
|
|
596
|
+
# will also run on queue 'level4'. The second ChidlWorker will, however, run
|
|
597
|
+
# on queue 'level3', as explained above.
|
|
598
|
+
ParentWorker.schedule(queue: 'level4', args: [some_arg])
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
|
|
548
604
|
## Extensions
|
|
549
605
|
**Note**: Extensions are not available when using cloudtasker via ActiveJob.
|
|
550
606
|
|
data/cloudtasker.gemspec
CHANGED
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
29
29
|
spec.require_paths = ['lib']
|
|
30
30
|
|
|
31
|
-
spec.required_ruby_version = '>=
|
|
31
|
+
spec.required_ruby_version = '>= 3.0'
|
|
32
32
|
|
|
33
33
|
spec.add_dependency 'activesupport'
|
|
34
34
|
spec.add_dependency 'connection_pool'
|
data/docs/UNIQUE_JOBS.md
CHANGED
|
@@ -70,6 +70,7 @@ For each lock strategy the table specifies the lock period (start/end) and which
|
|
|
70
70
|
| `until_executing` | The job is scheduled | The job starts processing | `reject` (default) or `raise` |
|
|
71
71
|
| `while_executing` | The job starts processing | The job ends processing | `reject` (default), `reschedule` or `raise` |
|
|
72
72
|
| `until_executed` | The job is scheduled | The job ends processing | `reject` (default) or `raise` |
|
|
73
|
+
| `until_completed` | The job is scheduled | The job completes successfully or a `DeadWorkerError` is raised. Supported since `v0.15.rc1`. | `reject` (default) or `raise` |
|
|
73
74
|
|
|
74
75
|
## Available conflict strategies
|
|
75
76
|
|
data/gemfiles/rails_6.1.gemfile
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
gem "appraisal"
|
|
5
|
+
gem "appraisal"
|
|
6
6
|
gem "bundler", "~> 2.0"
|
|
7
7
|
gem "rake", ">= 12.3.3"
|
|
8
8
|
gem "rspec", "~> 3.0"
|
|
@@ -14,5 +14,7 @@ gem "timecop"
|
|
|
14
14
|
gem "webmock"
|
|
15
15
|
gem "rails", "~> 6.1.0"
|
|
16
16
|
gem "rspec-rails"
|
|
17
|
+
gem "mutex_m"
|
|
18
|
+
gem "drb"
|
|
17
19
|
|
|
18
20
|
gemspec path: "../"
|
data/gemfiles/rails_7.0.gemfile
CHANGED
data/gemfiles/rails_7.1.gemfile
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
gem "appraisal"
|
|
5
|
+
gem "appraisal"
|
|
6
6
|
gem "bundler", "~> 2.0"
|
|
7
7
|
gem "rake", ">= 12.3.3"
|
|
8
8
|
gem "rspec", "~> 3.0"
|
|
@@ -12,7 +12,7 @@ gem "rubocop-rspec", "~> 3.0.1"
|
|
|
12
12
|
gem "semantic_logger"
|
|
13
13
|
gem "timecop"
|
|
14
14
|
gem "webmock"
|
|
15
|
-
gem "rails", "~>
|
|
15
|
+
gem "rails", "~> 8.0"
|
|
16
16
|
gem "rspec-rails"
|
|
17
17
|
|
|
18
18
|
gemspec path: "../"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
gem "appraisal"
|
|
5
|
+
gem "appraisal"
|
|
6
6
|
gem "bundler", "~> 2.0"
|
|
7
7
|
gem "rake", ">= 12.3.3"
|
|
8
8
|
gem "rspec", "~> 3.0"
|
|
@@ -12,7 +12,7 @@ gem "rubocop-rspec", "~> 3.0.1"
|
|
|
12
12
|
gem "semantic_logger"
|
|
13
13
|
gem "timecop"
|
|
14
14
|
gem "webmock"
|
|
15
|
-
gem "rails", "~>
|
|
15
|
+
gem "rails", "~> 8.1"
|
|
16
16
|
gem "rspec-rails"
|
|
17
17
|
|
|
18
18
|
gemspec path: "../"
|
|
@@ -66,7 +66,7 @@ module Cloudtasker
|
|
|
66
66
|
payload = payload.merge(schedule_time: payload[:schedule_time].to_i)
|
|
67
67
|
|
|
68
68
|
# Save task
|
|
69
|
-
task = new(**payload
|
|
69
|
+
task = new(**payload, id: id)
|
|
70
70
|
queue << task
|
|
71
71
|
|
|
72
72
|
# Execute task immediately if in testing and inline mode enabled
|
|
@@ -9,7 +9,7 @@ module Cloudtasker
|
|
|
9
9
|
class RedisTask
|
|
10
10
|
attr_reader :id, :http_request, :schedule_time, :retries, :queue, :dispatch_deadline
|
|
11
11
|
|
|
12
|
-
RETRY_INTERVAL =
|
|
12
|
+
RETRY_INTERVAL = Config::LOCAL_SERVER_RETRY_DELAY
|
|
13
13
|
|
|
14
14
|
#
|
|
15
15
|
# Return the Cloudtasker redis client
|
|
@@ -89,7 +89,7 @@ module Cloudtasker
|
|
|
89
89
|
# Save job
|
|
90
90
|
redis.write(key(id), payload)
|
|
91
91
|
redis.sadd(key, [id])
|
|
92
|
-
new(**payload
|
|
92
|
+
new(**payload, id: id)
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
#
|
|
@@ -103,7 +103,7 @@ module Cloudtasker
|
|
|
103
103
|
gid = key(id)
|
|
104
104
|
return nil unless (payload = redis.fetch(gid))
|
|
105
105
|
|
|
106
|
-
new(**payload
|
|
106
|
+
new(**payload, id: id)
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
#
|
data/lib/cloudtasker/config.rb
CHANGED
|
@@ -71,6 +71,9 @@ module Cloudtasker
|
|
|
71
71
|
# failures due to the instance being unreachable.
|
|
72
72
|
DEFAULT_MAX_RETRY_ATTEMPTS = 25
|
|
73
73
|
|
|
74
|
+
# How long to wait between retries in local server mode
|
|
75
|
+
LOCAL_SERVER_RETRY_DELAY = (ENV['CLOUDTASKER_LOCAL_RETRY_DELAY'] || 20).to_i # seconds
|
|
76
|
+
|
|
74
77
|
PROCESSOR_HOST_MISSING = <<~DOC
|
|
75
78
|
Missing host for processing.
|
|
76
79
|
Please specify a processor hostname in form of `https://some-public-dns.example.com`'
|
|
@@ -132,45 +132,25 @@ module Cloudtasker
|
|
|
132
132
|
list
|
|
133
133
|
end
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
super
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
else
|
|
155
|
-
#
|
|
156
|
-
# Delegate all methods to the redis client.
|
|
157
|
-
# Ruby 3 delegation method style.
|
|
158
|
-
#
|
|
159
|
-
# @param [String, Symbol] name The method to delegate.
|
|
160
|
-
# @param [Array<any>] *args The list of method positional arguments.
|
|
161
|
-
# @param [Hash<any>] *kwargs The list of method keyword arguments.
|
|
162
|
-
# @param [Proc] &block Block passed to the method.
|
|
163
|
-
#
|
|
164
|
-
# @return [Any] The method return value
|
|
165
|
-
#
|
|
166
|
-
def method_missing(name, *args, **kwargs, &block)
|
|
167
|
-
if Redis.method_defined?(name)
|
|
168
|
-
client.with { |c| c.send(name, *args, **kwargs, &block) }
|
|
169
|
-
else
|
|
170
|
-
super
|
|
171
|
-
end
|
|
135
|
+
#
|
|
136
|
+
# Delegate all methods to the redis client.
|
|
137
|
+
# Ruby 3 delegation method style.
|
|
138
|
+
#
|
|
139
|
+
# @param [String, Symbol] name The method to delegate.
|
|
140
|
+
# @param [Array<any>] *args The list of method positional arguments.
|
|
141
|
+
# @param [Hash<any>] *kwargs The list of method keyword arguments.
|
|
142
|
+
# @param [Proc] &block Block passed to the method.
|
|
143
|
+
#
|
|
144
|
+
# @return [Any] The method return value
|
|
145
|
+
#
|
|
146
|
+
def method_missing(name, ...)
|
|
147
|
+
if Redis.method_defined?(name)
|
|
148
|
+
client.with { |c| c.send(name, ...) }
|
|
149
|
+
else
|
|
150
|
+
super
|
|
172
151
|
end
|
|
173
152
|
end
|
|
153
|
+
|
|
174
154
|
#
|
|
175
155
|
# Check if the class respond to a certain method.
|
|
176
156
|
#
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cloudtasker
|
|
4
|
+
module UniqueJob
|
|
5
|
+
module Lock
|
|
6
|
+
# Conflict if any other job with the same args is scheduled or moved to execution
|
|
7
|
+
# while the first job is pending or executing. Unlocks only on successful completion
|
|
8
|
+
# or when a DeadWorkerError is raised.
|
|
9
|
+
class UntilCompleted < BaseLock
|
|
10
|
+
#
|
|
11
|
+
# Acquire a lock for the job and trigger a conflict
|
|
12
|
+
# if the lock could not be acquired.
|
|
13
|
+
#
|
|
14
|
+
def schedule(&block)
|
|
15
|
+
job.lock!
|
|
16
|
+
yield
|
|
17
|
+
rescue LockError
|
|
18
|
+
conflict_instance.on_schedule(&block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
#
|
|
22
|
+
# Acquire a lock for the job and trigger a conflict
|
|
23
|
+
# if the lock could not be acquired.
|
|
24
|
+
#
|
|
25
|
+
def execute(&block)
|
|
26
|
+
job.lock!
|
|
27
|
+
yield
|
|
28
|
+
# Unlock on successful completion
|
|
29
|
+
job.unlock!
|
|
30
|
+
rescue LockError
|
|
31
|
+
conflict_instance.on_execute(&block)
|
|
32
|
+
rescue Cloudtasker::DeadWorkerError
|
|
33
|
+
# Unlock when DeadWorkerError is raised
|
|
34
|
+
job.unlock!
|
|
35
|
+
raise
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/cloudtasker/version.rb
CHANGED
data/lib/cloudtasker/worker.rb
CHANGED
|
@@ -96,7 +96,7 @@ module Cloudtasker
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
#
|
|
99
|
-
# Enqueue worker in the
|
|
99
|
+
# Enqueue worker in the background.
|
|
100
100
|
#
|
|
101
101
|
# @param [Array<any>] *args List of worker arguments
|
|
102
102
|
#
|
|
@@ -130,6 +130,20 @@ module Cloudtasker
|
|
|
130
130
|
schedule(args: args, time_at: time_at)
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
+
#
|
|
134
|
+
# Perform a worker inline, without sending it to the queue for processing.
|
|
135
|
+
#
|
|
136
|
+
# Middlewares (unique job, batch etc.) will still be invoked as if the job
|
|
137
|
+
# had been scheduled.
|
|
138
|
+
#
|
|
139
|
+
# @param [Array<any>] *args List of worker arguments
|
|
140
|
+
#
|
|
141
|
+
# @return [Any] The result of the worker perform method.
|
|
142
|
+
#
|
|
143
|
+
def perform_now(*args)
|
|
144
|
+
new(job_args: args).execute
|
|
145
|
+
end
|
|
146
|
+
|
|
133
147
|
#
|
|
134
148
|
# Enqueue a worker with explicity options.
|
|
135
149
|
#
|
|
@@ -184,7 +198,12 @@ module Cloudtasker
|
|
|
184
198
|
# @return [String] The name of queue.
|
|
185
199
|
#
|
|
186
200
|
def job_queue
|
|
187
|
-
(
|
|
201
|
+
(
|
|
202
|
+
@job_queue ||=
|
|
203
|
+
Thread.current[:cloudtasker_propagated_queue] ||
|
|
204
|
+
self.class.cloudtasker_options_hash[:queue] ||
|
|
205
|
+
Config::DEFAULT_JOB_QUEUE
|
|
206
|
+
).to_s
|
|
188
207
|
end
|
|
189
208
|
|
|
190
209
|
#
|
|
@@ -215,7 +234,7 @@ module Cloudtasker
|
|
|
215
234
|
#
|
|
216
235
|
# Execute the worker by calling the `perform` with the args.
|
|
217
236
|
#
|
|
218
|
-
# @return [Any] The result of the perform.
|
|
237
|
+
# @return [Any] The result of the worker perform method.
|
|
219
238
|
#
|
|
220
239
|
def execute
|
|
221
240
|
logger.info('Starting job...')
|
|
@@ -436,6 +455,10 @@ module Cloudtasker
|
|
|
436
455
|
def execute_middleware_chain
|
|
437
456
|
self.perform_started_at = Time.now
|
|
438
457
|
|
|
458
|
+
# Store the parent worker queue so as to propagate it to the child workers
|
|
459
|
+
# See: #job_queue
|
|
460
|
+
Thread.current[:cloudtasker_propagated_queue] = job_queue if self.class.cloudtasker_options_hash[:propagate_queue]
|
|
461
|
+
|
|
439
462
|
Cloudtasker.config.server_middleware.invoke(self) do
|
|
440
463
|
# Immediately abort the job if it is already dead
|
|
441
464
|
flag_as_dead if job_dead?
|
|
@@ -454,6 +477,7 @@ module Cloudtasker
|
|
|
454
477
|
end
|
|
455
478
|
ensure
|
|
456
479
|
self.perform_ended_at = Time.now
|
|
480
|
+
Thread.current[:cloudtasker_propagated_queue] = nil
|
|
457
481
|
end
|
|
458
482
|
end
|
|
459
483
|
end
|
|
@@ -184,9 +184,9 @@ module Cloudtasker
|
|
|
184
184
|
#
|
|
185
185
|
# @return [Any] The method return value
|
|
186
186
|
#
|
|
187
|
-
def method_missing(name,
|
|
187
|
+
def method_missing(name, ...)
|
|
188
188
|
if logger.respond_to?(name)
|
|
189
|
-
logger.send(name,
|
|
189
|
+
logger.send(name, ...)
|
|
190
190
|
else
|
|
191
191
|
super
|
|
192
192
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cloudtasker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.15.rc2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Arnaud Lachaume
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-11-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -117,7 +117,6 @@ extensions: []
|
|
|
117
117
|
extra_rdoc_files: []
|
|
118
118
|
files:
|
|
119
119
|
- ".github/workflows/lint_rubocop.yml"
|
|
120
|
-
- ".github/workflows/test_ruby_2.7.yml"
|
|
121
120
|
- ".github/workflows/test_ruby_3.x.yml"
|
|
122
121
|
- ".gitignore"
|
|
123
122
|
- ".rspec"
|
|
@@ -149,11 +148,11 @@ files:
|
|
|
149
148
|
- gemfiles/google_cloud_tasks_1.5.gemfile
|
|
150
149
|
- gemfiles/google_cloud_tasks_2.0.gemfile
|
|
151
150
|
- gemfiles/google_cloud_tasks_2.1.gemfile
|
|
152
|
-
- gemfiles/rails_5.2.gemfile
|
|
153
|
-
- gemfiles/rails_6.0.gemfile
|
|
154
151
|
- gemfiles/rails_6.1.gemfile
|
|
155
152
|
- gemfiles/rails_7.0.gemfile
|
|
156
153
|
- gemfiles/rails_7.1.gemfile
|
|
154
|
+
- gemfiles/rails_8.0.gemfile
|
|
155
|
+
- gemfiles/rails_8.1.gemfile
|
|
157
156
|
- gemfiles/semantic_logger_3.4.gemfile
|
|
158
157
|
- gemfiles/semantic_logger_4.6.gemfile
|
|
159
158
|
- gemfiles/semantic_logger_4.7.0.gemfile
|
|
@@ -201,6 +200,7 @@ files:
|
|
|
201
200
|
- lib/cloudtasker/unique_job/job.rb
|
|
202
201
|
- lib/cloudtasker/unique_job/lock/base_lock.rb
|
|
203
202
|
- lib/cloudtasker/unique_job/lock/no_op.rb
|
|
203
|
+
- lib/cloudtasker/unique_job/lock/until_completed.rb
|
|
204
204
|
- lib/cloudtasker/unique_job/lock/until_executed.rb
|
|
205
205
|
- lib/cloudtasker/unique_job/lock/until_executing.rb
|
|
206
206
|
- lib/cloudtasker/unique_job/lock/while_executing.rb
|
|
@@ -230,7 +230,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
230
230
|
requirements:
|
|
231
231
|
- - ">="
|
|
232
232
|
- !ruby/object:Gem::Version
|
|
233
|
-
version:
|
|
233
|
+
version: '3.0'
|
|
234
234
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
235
235
|
requirements:
|
|
236
236
|
- - ">="
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
name: Ruby 2.7
|
|
2
|
-
|
|
3
|
-
on: [push, pull_request]
|
|
4
|
-
|
|
5
|
-
jobs:
|
|
6
|
-
build:
|
|
7
|
-
runs-on: ubuntu-latest
|
|
8
|
-
strategy:
|
|
9
|
-
matrix:
|
|
10
|
-
ruby:
|
|
11
|
-
- '2.7'
|
|
12
|
-
appraisal:
|
|
13
|
-
- 'google_cloud_tasks_1.0'
|
|
14
|
-
- 'google_cloud_tasks_1.1'
|
|
15
|
-
- 'google_cloud_tasks_1.2'
|
|
16
|
-
- 'google_cloud_tasks_1.3'
|
|
17
|
-
- 'google_cloud_tasks_1.4'
|
|
18
|
-
- 'google_cloud_tasks_1.5'
|
|
19
|
-
- 'google_cloud_tasks_2.0'
|
|
20
|
-
- 'google_cloud_tasks_2.1'
|
|
21
|
-
- 'rails_5.2'
|
|
22
|
-
- 'rails_6.0'
|
|
23
|
-
- 'rails_6.1'
|
|
24
|
-
- 'rails_7.0'
|
|
25
|
-
- 'semantic_logger_3.4'
|
|
26
|
-
- 'semantic_logger_4.6'
|
|
27
|
-
- 'semantic_logger_4.7.0'
|
|
28
|
-
- 'semantic_logger_4.7.2'
|
|
29
|
-
env:
|
|
30
|
-
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.appraisal }}.gemfile
|
|
31
|
-
steps:
|
|
32
|
-
- uses: actions/checkout@v2
|
|
33
|
-
- uses: zhulik/redis-action@1.1.0
|
|
34
|
-
- uses: ruby/setup-ruby@v1
|
|
35
|
-
with:
|
|
36
|
-
ruby-version: ${{ matrix.ruby }}
|
|
37
|
-
bundler-cache: true
|
|
38
|
-
- run: bundle exec rspec
|