cloudtasker 0.10.rc6 → 0.10.rc7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/README.md +106 -10
- data/lib/cloudtasker/backend/memory_task.rb +12 -2
- data/lib/cloudtasker/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c5440326c0fa695e469a341d58b976bd4027179440a607ce34c15c9dd4d697e
|
4
|
+
data.tar.gz: 671c2bcf90c199c68136a14efa62410d17e3a850dad1e6b5bf6a02b083169d75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6adad797eedb6ff0d589ea2dfa6b109709f629ad82cf64e9755e7da235b4a4fb902d4c48794981dcd527a6933196686a72fce46b2572912fd84b1a3396bcd33
|
7
|
+
data.tar.gz: 78fa73bafda04c16b46bed2bd8930e5e5ef3badf046f2e665b41d156e9644c20468788a0ffa173fcb6585bdb24a1bdcff599be11f41a5420c1302747e209bc52
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -6,11 +6,11 @@ Background jobs for Ruby using Google Cloud Tasks.
|
|
6
6
|
|
7
7
|
Cloudtasker provides an easy to manage interface to Google Cloud Tasks for background job processing. Workers can be defined programmatically using the Cloudtasker DSL and enqueued for processing using a simple to use API.
|
8
8
|
|
9
|
-
Cloudtasker is particularly suited for serverless applications only responding to HTTP requests and where running a dedicated job processing is not an option (e.g. deploy via [Cloud Run](https://cloud.google.com/run)). All jobs enqueued in Cloud Tasks via Cloudtasker eventually get processed by your application via HTTP requests.
|
9
|
+
Cloudtasker is particularly suited for serverless applications only responding to HTTP requests and where running a dedicated job processing server is not an option (e.g. deploy via [Cloud Run](https://cloud.google.com/run)). All jobs enqueued in Cloud Tasks via Cloudtasker eventually get processed by your application via HTTP requests.
|
10
10
|
|
11
11
|
Cloudtasker also provides optional modules for running [cron jobs](docs/CRON_JOBS.md), [batch jobs](docs/BATCH_JOBS.md) and [unique jobs](docs/UNIQUE_JOBS.md).
|
12
12
|
|
13
|
-
A local processing server is also available
|
13
|
+
A local processing server is also available for development. This local server processes jobs in lieu of Cloud Tasks and allows you to work offline.
|
14
14
|
|
15
15
|
## Summary
|
16
16
|
|
@@ -34,7 +34,11 @@ A local processing server is also available in development. This local server pr
|
|
34
34
|
1. [HTTP Error codes](#http-error-codes)
|
35
35
|
2. [Error callbacks](#error-callbacks)
|
36
36
|
3. [Max retries](#max-retries)
|
37
|
-
10. [
|
37
|
+
10. [Testing](#testing)
|
38
|
+
1. [Test helper setup](#test-helper-setup)
|
39
|
+
2. [In-memory queues](#in-memory-queues)
|
40
|
+
3. [Unit tests](#unit-tests)
|
41
|
+
11. [Best practices building workers](#best-practices-building-workers)
|
38
42
|
|
39
43
|
## Installation
|
40
44
|
|
@@ -48,7 +52,7 @@ And then execute:
|
|
48
52
|
|
49
53
|
$ bundle
|
50
54
|
|
51
|
-
Or install it yourself
|
55
|
+
Or install it yourself with:
|
52
56
|
|
53
57
|
$ gem install cloudtasker
|
54
58
|
|
@@ -218,7 +222,7 @@ Cloudtasker.configure do |config|
|
|
218
222
|
|
219
223
|
#
|
220
224
|
# Specify how many retries are allowed on jobs. This number of retries excludes any
|
221
|
-
# connectivity error
|
225
|
+
# connectivity error due to the application being down or unreachable.
|
222
226
|
#
|
223
227
|
# Default: 25
|
224
228
|
#
|
@@ -289,7 +293,7 @@ MyWorker.schedule(args: [arg1, arg2], time_at: Time.parse('2025-01-01 00:50:00Z'
|
|
289
293
|
MyWorker.schedule(args: [arg1, arg2], time_in: 5 * 60, queue: 'critical')
|
290
294
|
```
|
291
295
|
|
292
|
-
Cloudtasker also provides a helper for re-enqueuing jobs. Re-enqueued jobs keep the same
|
296
|
+
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.
|
293
297
|
|
294
298
|
E.g.
|
295
299
|
```ruby
|
@@ -474,7 +478,7 @@ The way contextual information is displayed depends on the logger itself. For ex
|
|
474
478
|
|
475
479
|
Contextual information can be customised globally and locally using a log context_processor. By default the `Cloudtasker::WorkerLogger` is configured the following way:
|
476
480
|
```ruby
|
477
|
-
Cloudtasker::WorkerLogger.log_context_processor = ->(worker) { worker.to_h.slice(:worker, :job_id, :job_meta) }
|
481
|
+
Cloudtasker::WorkerLogger.log_context_processor = ->(worker) { worker.to_h.slice(:worker, :job_id, :job_meta, :job_queue, :task_id) }
|
478
482
|
```
|
479
483
|
|
480
484
|
You can decide to add a global identifier for your worker logs using the following:
|
@@ -482,7 +486,7 @@ You can decide to add a global identifier for your worker logs using the followi
|
|
482
486
|
# config/initializers/cloudtasker.rb
|
483
487
|
|
484
488
|
Cloudtasker::WorkerLogger.log_context_processor = lambda { |worker|
|
485
|
-
worker.to_h.slice(:worker, :job_id, :job_meta).merge(app: 'my-app')
|
489
|
+
worker.to_h.slice(:worker, :job_id, :job_meta, :job_queue, :task_id).merge(app: 'my-app')
|
486
490
|
}
|
487
491
|
```
|
488
492
|
|
@@ -520,7 +524,7 @@ The Google Cloud Task UI (GCP console) lists all the tasks pending/retrying and
|
|
520
524
|
|
521
525
|
## Error Handling
|
522
526
|
|
523
|
-
Jobs
|
527
|
+
Jobs failures will return an HTTP error to Cloud Task and trigger a retry at a later time. The number of Cloud Task retries depends on the configuration of your queue in Cloud Tasks.
|
524
528
|
|
525
529
|
### HTTP Error codes
|
526
530
|
|
@@ -528,6 +532,7 @@ Jobs failing will automatically return the following HTTP error code to Cloud Ta
|
|
528
532
|
|
529
533
|
| Code | Description |
|
530
534
|
|------|-------------|
|
535
|
+
| 204 | The job was processed successfully |
|
531
536
|
| 205 | The job is dead and has been removed from the queue |
|
532
537
|
| 404 | The job has specified an incorrect worker class. |
|
533
538
|
| 422 | An error happened during the execution of the worker (`perform` method) |
|
@@ -566,7 +571,7 @@ By default jobs are retried 25 times - using an exponential backoff - before bei
|
|
566
571
|
|
567
572
|
Note that the number of retries set on your Cloud Task queue should be many times higher than the number of retries configured in Cloudtasker because Cloud Task also includes failures to connect to your application. Ideally set the number of retries to `unlimited` in Cloud Tasks.
|
568
573
|
|
569
|
-
**Note**: The `X-CloudTasks-TaskExecutionCount` header sent by Google Cloud Tasks and providing the number of retries outside of `HTTP 503` (instance not reachable) is currently bugged and remains at `0` all the time. Starting with `
|
574
|
+
**Note**: The `X-CloudTasks-TaskExecutionCount` header sent by Google Cloud Tasks and providing the number of retries outside of `HTTP 503` (instance not reachable) is currently bugged and remains at `0` all the time. Starting with `v0.10.rc3` Cloudtasker uses the `X-CloudTasks-TaskRetryCount` header to detect the number of retries. This header includes `HTTP 503` errors which means that if your application is down at some point, jobs will fail and these failures will be counted toward the maximum number of retries. A [bug report](https://issuetracker.google.com/issues/154532072) has been raised with GCP to address this issue. Once fixed we will revert to using `X-CloudTasks-TaskExecutionCount` to avoid counting `HTTP 503` as job failures.
|
570
575
|
|
571
576
|
E.g. Set max number of retries globally via the cloudtasker initializer.
|
572
577
|
```ruby
|
@@ -601,6 +606,97 @@ class SomeErrorWorker
|
|
601
606
|
end
|
602
607
|
```
|
603
608
|
|
609
|
+
## Testing
|
610
|
+
Cloudtasker provides several options to test your workers.
|
611
|
+
|
612
|
+
### Test helper setup
|
613
|
+
Require `cloudtasker/testing` in your `rails_helper.rb` (Rspec Rails) or `spec_helper.rb` (Rspec) or test unit helper file then enable one of the three modes:
|
614
|
+
|
615
|
+
```ruby
|
616
|
+
require 'cloudtasker/testing'
|
617
|
+
|
618
|
+
# Mode 1 (default): Push jobs to Google Cloud Tasks (env != development) or Redis (env == development)
|
619
|
+
Cloudtasker::Testing.enable!
|
620
|
+
|
621
|
+
# Mode 2: Push jobs to an in-memory queue. Jobs will not be processed until you call
|
622
|
+
# Cloudtasker::Worker.drain_all (process all jobs) or MyWorker.drain (process jobs for specific worker)
|
623
|
+
Cloudtasker::Testing.fake!
|
624
|
+
|
625
|
+
# Mode 3: Push jobs to an in-memory queue. Jobs will be processed immediately.
|
626
|
+
Cloudtasker::Testing.inline!
|
627
|
+
```
|
628
|
+
|
629
|
+
You can query the current testing mode with:
|
630
|
+
```ruby
|
631
|
+
Cloudtasker::Testing.enabled?
|
632
|
+
Cloudtasker::Testing.fake?
|
633
|
+
Cloudtasker::Testing.inline?
|
634
|
+
```
|
635
|
+
|
636
|
+
Each testing mode accepts a block argument to temporarily switch to it:
|
637
|
+
```ruby
|
638
|
+
# Enable fake mode for all tests
|
639
|
+
Cloudtasker::Testing.fake!
|
640
|
+
|
641
|
+
# Enable inline! mode temporarily for a given test
|
642
|
+
Cloudtasker.inline! do
|
643
|
+
MyWorker.perform_async(1,2)
|
644
|
+
end
|
645
|
+
```
|
646
|
+
|
647
|
+
Note that extension middlewares - e.g. unique job, batch job etc. - run in test mode. You can disable middlewares in your tests by adding the following to your test helper:
|
648
|
+
```ruby
|
649
|
+
# Remove all middlewares
|
650
|
+
Cloudtasker.configure do |c|
|
651
|
+
c.client_middleware.clear
|
652
|
+
c.server_middleware.clear
|
653
|
+
end
|
654
|
+
|
655
|
+
# Remove all unique job middlewares
|
656
|
+
Cloudtasker.configure do |c|
|
657
|
+
c.client_middleware.remove(Cloudtasker::UniqueJob::Middleware::Client)
|
658
|
+
c.server_middleware.remove(Cloudtasker::UniqueJob::Middleware::Server)
|
659
|
+
end
|
660
|
+
```
|
661
|
+
|
662
|
+
### In-memory queues
|
663
|
+
The `fake!` or `inline!` modes use in-memory queues, which can be queried and controlled using the following methods:
|
664
|
+
|
665
|
+
```ruby
|
666
|
+
# Perform all jobs in queue
|
667
|
+
Cloudtasker::Worker.drain_all
|
668
|
+
|
669
|
+
# Remove all jobs in queue
|
670
|
+
Cloudtasker::Worker.clear_all
|
671
|
+
|
672
|
+
# Perform all jobs in queue for a specific worker type
|
673
|
+
MyWorker.drain
|
674
|
+
|
675
|
+
# Return the list of jobs in queue for a specific worker type
|
676
|
+
MyWorker.jobs
|
677
|
+
```
|
678
|
+
|
679
|
+
### Unit tests
|
680
|
+
Below are examples of rspec tests. It is assumed that `Cloudtasker::Testing.fake!` has been set in the test helper.
|
681
|
+
|
682
|
+
**Example 1**: Testing that a job is scheduled
|
683
|
+
```ruby
|
684
|
+
describe 'worker scheduling'
|
685
|
+
subject(:enqueue_job) { MyWorker.perform_async(1,2) }
|
686
|
+
|
687
|
+
it { expect { enqueue_job }.to change(MyWorker.jobs, :size).by(1) }
|
688
|
+
end
|
689
|
+
```
|
690
|
+
|
691
|
+
**Example 2**: Testing job execution logic
|
692
|
+
```ruby
|
693
|
+
describe 'worker calls api'
|
694
|
+
subject { Cloudtasker::Testing.inline! { MyApiWorker.perform_async(1,2) } }
|
695
|
+
|
696
|
+
before { expect(MyApi).to receive(:fetch).and_return([]) }
|
697
|
+
it { is_expected.to be_truthy }
|
698
|
+
end
|
699
|
+
```
|
604
700
|
|
605
701
|
## Best practices building workers
|
606
702
|
|
@@ -8,6 +8,15 @@ module Cloudtasker
|
|
8
8
|
attr_accessor :job_retries
|
9
9
|
attr_reader :id, :http_request, :schedule_time, :queue
|
10
10
|
|
11
|
+
#
|
12
|
+
# Return true if we are in test inline execution mode.
|
13
|
+
#
|
14
|
+
# @return [Boolean] True if inline mode enabled.
|
15
|
+
#
|
16
|
+
def self.inline_mode?
|
17
|
+
defined?(Cloudtasker::Testing) && Cloudtasker::Testing.inline?
|
18
|
+
end
|
19
|
+
|
11
20
|
#
|
12
21
|
# Return the task queue. A worker class name
|
13
22
|
#
|
@@ -57,7 +66,7 @@ module Cloudtasker
|
|
57
66
|
queue << task
|
58
67
|
|
59
68
|
# Execute task immediately if in testing and inline mode enabled
|
60
|
-
task.execute if
|
69
|
+
task.execute if inline_mode?
|
61
70
|
|
62
71
|
task
|
63
72
|
end
|
@@ -157,8 +166,9 @@ module Cloudtasker
|
|
157
166
|
# Delete task
|
158
167
|
self.class.delete(id)
|
159
168
|
resp
|
160
|
-
rescue StandardError
|
169
|
+
rescue StandardError => e
|
161
170
|
self.job_retries += 1
|
171
|
+
raise(e) if self.class.inline_mode?
|
162
172
|
end
|
163
173
|
|
164
174
|
#
|
data/lib/cloudtasker/version.rb
CHANGED
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.10.
|
4
|
+
version: 0.10.rc7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arnaud Lachaume
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|