cloudtasker 0.7.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +3 -3
- data/CHANGELOG.md +41 -0
- data/README.md +145 -25
- data/_config.yml +1 -0
- data/app/controllers/cloudtasker/worker_controller.rb +21 -5
- data/cloudtasker.gemspec +2 -2
- data/docs/BATCH_JOBS.md +28 -3
- data/docs/CRON_JOBS.md +3 -1
- data/exe/cloudtasker +13 -1
- data/gemfiles/google_cloud_tasks_1.0.gemfile.lock +26 -9
- data/gemfiles/google_cloud_tasks_1.1.gemfile.lock +26 -9
- data/gemfiles/google_cloud_tasks_1.2.gemfile.lock +27 -10
- data/gemfiles/google_cloud_tasks_1.3.gemfile.lock +26 -9
- data/gemfiles/rails_5.2.gemfile.lock +28 -11
- data/gemfiles/rails_6.0.gemfile.lock +29 -12
- data/lib/cloudtasker.rb +1 -1
- data/lib/cloudtasker/backend/google_cloud_task.rb +65 -12
- data/lib/cloudtasker/backend/memory_task.rb +5 -3
- data/lib/cloudtasker/backend/redis_task.rb +24 -13
- data/lib/cloudtasker/batch/batch_progress.rb +11 -2
- data/lib/cloudtasker/batch/job.rb +18 -4
- data/lib/cloudtasker/cli.rb +6 -5
- data/lib/cloudtasker/cloud_task.rb +6 -2
- data/lib/cloudtasker/config.rb +33 -9
- data/lib/cloudtasker/cron/job.rb +2 -2
- data/lib/cloudtasker/cron/schedule.rb +26 -14
- data/lib/cloudtasker/local_server.rb +44 -22
- data/lib/cloudtasker/max_task_size_exceeded_error.rb +14 -0
- data/lib/cloudtasker/redis_client.rb +10 -7
- data/lib/cloudtasker/unique_job/job.rb +2 -2
- data/lib/cloudtasker/version.rb +1 -1
- data/lib/cloudtasker/worker.rb +45 -10
- data/lib/cloudtasker/worker_handler.rb +7 -5
- data/lib/cloudtasker/worker_logger.rb +1 -1
- data/lib/cloudtasker/worker_wrapper.rb +52 -0
- data/lib/tasks/setup_queue.rake +12 -2
- metadata +7 -6
- data/Gemfile.lock +0 -280
- data/lib/cloudtasker/railtie.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc46ef6ccfab1437c91a90c3cf3e4ee7b401fe5b453d8e61c7d8af09607f6695
|
4
|
+
data.tar.gz: 4a8192b395ff86ff1dba2d06d677237273cef952533e41b199256db3bad2cc0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 387f5202bb42b3903cf7cede2fcc84978f8ca0bf0e61eadd73d8e8fbf2d4c29ce5bb15caa749b22386ec3e5363936afb93f9600b6fd0886734909937512303bd
|
7
|
+
data.tar.gz: 6b3a4a77d35d1c885e623e7e737ee9008fd16e05568e3f5f2bc8e82b9ce39feecfcaf875c4b94c6dc94ecb0a68855e651759980488b1eb633bb5ca645f254c73
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
language: ruby
|
3
3
|
cache: bundler
|
4
4
|
rvm:
|
5
|
-
- 2.3
|
6
|
-
- 2.4
|
7
5
|
- 2.5.5
|
6
|
+
services:
|
7
|
+
- redis-server
|
8
8
|
before_install: gem install bundler -v 2.0.2
|
9
|
-
before_script: rubocop
|
9
|
+
before_script: bundle exec rubocop
|
10
10
|
gemfile:
|
11
11
|
- gemfiles/google_cloud_tasks_1.0.gemfile
|
12
12
|
- gemfiles/google_cloud_tasks_1.1.gemfile
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,46 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v0.9.1](https://github.com/keypup-io/cloudtasker/tree/v0.9.1) (2020-02-11)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.9.0...v0.9.1)
|
6
|
+
|
7
|
+
**Fixed bugs:**
|
8
|
+
- Cloud Task: raise `Cloudtasker::MaxTaskSizeExceededError` if job payload exceeds 100 KB. This is mainly to have production parity in development when running the local processing server.
|
9
|
+
|
10
|
+
## [v0.9.0](https://github.com/keypup-io/cloudtasker/tree/v0.9.0) (2020-01-23)
|
11
|
+
|
12
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.8.2...v0.9.0)
|
13
|
+
|
14
|
+
**Fixed bugs:**
|
15
|
+
- Cloud Task: Base64 encode task body to support UTF-8 characters (e.g. emojis).
|
16
|
+
- Redis: Restrict to one connection (class level) to avoid too many DNS lookups
|
17
|
+
|
18
|
+
**Migration**
|
19
|
+
For Sinatra applications please update your Cloudtasker controller according to [this diff](https://github.com/keypup-io/cloudtasker/commit/311fa8f9beec91fbae012164a25b2ee6e261a2e4#diff-c2a0ea6c6e6c31c749d2e1acdc574f0f).
|
20
|
+
|
21
|
+
## [v0.8.2](https://github.com/keypup-io/cloudtasker/tree/v0.8.2) (2019-12-05)
|
22
|
+
|
23
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.8.1...v0.8.2)
|
24
|
+
|
25
|
+
**Fixed bugs:**
|
26
|
+
- Config: do not add processor host to `Rails.application.config.hosts` if originally empty.
|
27
|
+
|
28
|
+
## [v0.8.1](https://github.com/keypup-io/cloudtasker/tree/v0.8.1) (2019-12-03)
|
29
|
+
|
30
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.8.0...v0.8.1)
|
31
|
+
|
32
|
+
**Fixed bugs:**
|
33
|
+
- Local dev server: ensure job queue name is kept when taks is retried
|
34
|
+
- Rails/Controller: bypass Rails munge logic to preserve nil values inside job arguments.
|
35
|
+
|
36
|
+
## [v0.8.0](https://github.com/keypup-io/cloudtasker/tree/v0.8.0) (2019-11-27)
|
37
|
+
|
38
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.7.0...v0.8.0)
|
39
|
+
|
40
|
+
## [v0.7.0](https://github.com/keypup-io/cloudtasker/tree/v0.7.0) (2019-11-25)
|
41
|
+
|
42
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.6.0...v0.7.0)
|
43
|
+
|
3
44
|
## [v0.6.0](https://github.com/keypup-io/cloudtasker/tree/v0.6.0) (2019-11-25)
|
4
45
|
|
5
46
|
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.5.0...v0.6.0)
|
data/README.md
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/keypup-io/cloudtasker.svg?branch=master)](https://travis-ci.org/keypup-io/cloudtasker) [![Gem Version](https://badge.fury.io/rb/cloudtasker.svg)](https://badge.fury.io/rb/cloudtasker)
|
2
|
+
|
1
3
|
# Cloudtasker
|
2
4
|
|
3
5
|
Background jobs for Ruby using Google Cloud Tasks.
|
4
6
|
|
5
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.
|
6
8
|
|
7
|
-
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
|
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.
|
8
10
|
|
9
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).
|
10
12
|
|
11
|
-
A local processing server is also available in development. This local server processes jobs in lieu of Cloud Tasks and
|
13
|
+
A local processing server is also available in development. This local server processes jobs in lieu of Cloud Tasks and allows you to work offline.
|
12
14
|
|
13
15
|
## Summary
|
14
16
|
|
@@ -18,18 +20,21 @@ A local processing server is also available in development. This local server pr
|
|
18
20
|
1. [Cloud Tasks authentication & permissions](#cloud-tasks-authentication--permissions)
|
19
21
|
2. [Cloudtasker initializer](#cloudtasker-initializer)
|
20
22
|
4. [Enqueuing jobs](#enqueuing-jobs)
|
21
|
-
5. [
|
22
|
-
|
23
|
+
5. [Managing worker queues](#managing-worker-queues)
|
24
|
+
1. [Creating queues](#creating-queues)
|
25
|
+
2. [Assigning queues to workers](#assigning-queues-to-workers)
|
26
|
+
6. [Extensions](#extensions)
|
27
|
+
7. [Working locally](#working-locally)
|
23
28
|
1. [Option 1: Cloudtasker local server](#option-1-cloudtasker-local-server)
|
24
29
|
2. [Option 2: Using ngrok](#option-2-using-ngrok)
|
25
|
-
|
30
|
+
8. [Logging](#logging)
|
26
31
|
1. [Configuring a logger](#configuring-a-logger)
|
27
32
|
2. [Logging context](#logging-context)
|
28
|
-
|
33
|
+
9. [Error Handling](#error-handling)
|
29
34
|
1. [HTTP Error codes](#http-error-codes)
|
30
35
|
2. [Error callbacks](#error-callbacks)
|
31
36
|
3. [Max retries](#max-retries)
|
32
|
-
|
37
|
+
10. [Best practices building workers](#best-practices-building-workers)
|
33
38
|
|
34
39
|
## Installation
|
35
40
|
|
@@ -104,7 +109,7 @@ Open a Rails console and enqueue some jobs
|
|
104
109
|
DummyWorker.perform_async('foo')
|
105
110
|
|
106
111
|
# Process job in 60 seconds
|
107
|
-
DummyWorker.perform_in(
|
112
|
+
DummyWorker.perform_in(60, 'foo')
|
108
113
|
```
|
109
114
|
|
110
115
|
Your Rails logs should display the following:
|
@@ -157,13 +162,31 @@ Cloudtasker.configure do |config|
|
|
157
162
|
# config.secret = 'some-long-token'
|
158
163
|
|
159
164
|
#
|
160
|
-
# Specify the details of your Google Cloud Task
|
165
|
+
# Specify the details of your Google Cloud Task location.
|
161
166
|
#
|
162
167
|
# This not required in development using the Cloudtasker local server.
|
163
168
|
#
|
164
169
|
config.gcp_location_id = 'us-central1' # defaults to 'us-east1'
|
165
170
|
config.gcp_project_id = 'my-gcp-project'
|
166
|
-
|
171
|
+
|
172
|
+
#
|
173
|
+
# Specify the namespace for your Cloud Task queues.
|
174
|
+
#
|
175
|
+
# The gem assumes that a least a default queue named 'my-app-default'
|
176
|
+
# exists in Cloud Tasks. You can create this default queue using the
|
177
|
+
# gcloud SDK or via the `rake cloudtasker:setup_queue` task if you use Rails.
|
178
|
+
#
|
179
|
+
# Workers can be scheduled on different queues. The name of the queue
|
180
|
+
# in Cloud Tasks is always assumed to be prefixed with the prefix below.
|
181
|
+
#
|
182
|
+
# E.g.
|
183
|
+
# Setting `cloudtasker_options queue: 'critical'` on a worker means that
|
184
|
+
# the worker will be pushed to 'my-app-critical' in Cloud Tasks.
|
185
|
+
#
|
186
|
+
# Specific queues can be created in Cloud Tasks using the gcloud SDK or
|
187
|
+
# via the `rake cloudtasker:setup_queue name=<queue_name>` task.
|
188
|
+
#
|
189
|
+
config.gcp_queue_prefix = 'my-app'
|
167
190
|
|
168
191
|
#
|
169
192
|
# Specify the publicly accessible host for your application
|
@@ -215,7 +238,7 @@ Cloudtasker.configure do |config|
|
|
215
238
|
end
|
216
239
|
```
|
217
240
|
|
218
|
-
If
|
241
|
+
If the default queue `<gcp_queue_prefix>-default` does not exist in Cloud Tasks you should [create it using the gcloud sdk](https://cloud.google.com/tasks/docs/creating-queues).
|
219
242
|
|
220
243
|
Alternatively with Rails you can simply run the following rake task if you have queue admin permissions (`cloudtasks.queues.get` and `cloudtasks.queues.create`).
|
221
244
|
```bash
|
@@ -235,10 +258,15 @@ MyWorker.perform_in(5 * 60, arg1, arg2)
|
|
235
258
|
# or with Rails
|
236
259
|
MyWorker.perform_in(5.minutes, arg1, arg2)
|
237
260
|
|
238
|
-
# Worker will be processed on specific date
|
261
|
+
# Worker will be processed on a specific date
|
239
262
|
MyWorker.perform_at(Time.parse('2025-01-01 00:50:00Z'), arg1, arg2)
|
240
263
|
# also with Rails
|
241
264
|
MyWorker.perform_at(3.days.from_now, arg1, arg2)
|
265
|
+
|
266
|
+
# With all options, including which queue to run the worker on.
|
267
|
+
MyWorker.schedule(args: [arg1, arg2], time_at: Time.parse('2025-01-01 00:50:00Z'), queue: 'critical')
|
268
|
+
# or
|
269
|
+
MyWorker.schedule(args: [arg1, arg2], time_in: 5 * 60, queue: 'critical')
|
242
270
|
```
|
243
271
|
|
244
272
|
Cloudtasker also provides a helper for re-enqueuing jobs. Re-enqueued jobs keep the same worker 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.
|
@@ -262,6 +290,52 @@ class FetchResourceWorker
|
|
262
290
|
end
|
263
291
|
```
|
264
292
|
|
293
|
+
## Managing worker queues
|
294
|
+
|
295
|
+
Cloudtasker allows you to manage several queues and distribute workers across them based on job priority. By default jobs are pushed to the `default` queue, which is `<gcp_queue_prefix>-default` in Cloud Tasks.
|
296
|
+
|
297
|
+
### Creating queues
|
298
|
+
|
299
|
+
More queues can be created using the gcloud sdk or the `cloudtasker:setup_queue` rake task.
|
300
|
+
|
301
|
+
E.g. Create a `critical` queue with a concurrency of 5 via the gcloud SDK
|
302
|
+
```bash
|
303
|
+
gcloud tasks queues create <gcp_queue_prefix>-critical --max-concurrent-dispatches=5
|
304
|
+
```
|
305
|
+
|
306
|
+
E.g. Create a `real-time` queue with a concurrency of 15 via the rake task (Rails only)
|
307
|
+
```bash
|
308
|
+
rake cloudtasker:setup_queue name=real-time concurrency=15
|
309
|
+
```
|
310
|
+
|
311
|
+
When running the Cloudtasker local processing server, you can specify the concurrency for each queue using:
|
312
|
+
```bash
|
313
|
+
cloudtasker -q critical,5 -q important,4 -q default,3
|
314
|
+
```
|
315
|
+
|
316
|
+
### Assigning queues to workers
|
317
|
+
|
318
|
+
Queues can be assigned to workers via the `cloudtasker_options` directive on the worker class:
|
319
|
+
|
320
|
+
```ruby
|
321
|
+
# app/workers/critical_worker.rb
|
322
|
+
|
323
|
+
class CriticalWorker
|
324
|
+
include Cloudtasker::Worker
|
325
|
+
|
326
|
+
cloudtasker_options queue: :critical
|
327
|
+
|
328
|
+
def perform(some_arg)
|
329
|
+
logger.info("This is a critical job run with arg=#{some_arg}.")
|
330
|
+
end
|
331
|
+
end
|
332
|
+
```
|
333
|
+
|
334
|
+
Queues can also be assigned at runtime when scheduling a job:
|
335
|
+
```ruby
|
336
|
+
CriticalWorker.schedule(args: [1], queue: :important)
|
337
|
+
```
|
338
|
+
|
265
339
|
## Extensions
|
266
340
|
Cloudtasker comes with three optional features:
|
267
341
|
- Cron Jobs [[docs](docs/CRON_JOBS.md)]: Run jobs at fixed intervals.
|
@@ -277,7 +351,7 @@ When working locally on your application it is usually not possible to have a pu
|
|
277
351
|
### Option 1: Cloudtasker local server
|
278
352
|
The Cloudtasker local server is a ruby daemon that looks for jobs pushed to Redis and sends them to your application via HTTP POST requests. The server mimics the way Google Cloud Tasks works, but locally!
|
279
353
|
|
280
|
-
You can configure your
|
354
|
+
You can configure your application to use the Cloudtasker local server using the following initializer:
|
281
355
|
```ruby
|
282
356
|
# config/initializers/cloudtasker.rb
|
283
357
|
|
@@ -299,15 +373,20 @@ bundle exec cloudtasker
|
|
299
373
|
You can as well define a Procfile to manage the cloudtasker process via foreman. Then use `foreman start` to launch both your Rails server and the Cloudtasker local server.
|
300
374
|
```yaml
|
301
375
|
# Procfile
|
302
|
-
web: rails s
|
303
|
-
worker: cloudtasker
|
376
|
+
web: bundle exec rails s
|
377
|
+
worker: bundle exec cloudtasker
|
378
|
+
```
|
379
|
+
|
380
|
+
Note that the local development server runs with `5` concurrent threads by default. You can tune the number of threads per queue by running `cloudtasker` the following options:
|
381
|
+
```bash
|
382
|
+
bundle exec cloudtasker -q critical,5 -q important,4 -q default,3
|
304
383
|
```
|
305
384
|
|
306
385
|
### Option 2: Using ngrok
|
307
386
|
|
308
387
|
Want to test your application end to end with Google Cloud Task? Then [ngrok](https://ngrok.io) is the way to go.
|
309
388
|
|
310
|
-
First start your ngrok tunnel
|
389
|
+
First start your ngrok tunnel:
|
311
390
|
```bash
|
312
391
|
ngrok http 3000
|
313
392
|
```
|
@@ -318,9 +397,9 @@ Take note of your ngrok domain and configure Cloudtasker to use Google Cloud Tas
|
|
318
397
|
|
319
398
|
Cloudtasker.configure do |config|
|
320
399
|
# Specify your Google Cloud Task queue configuration
|
321
|
-
|
322
|
-
|
323
|
-
|
400
|
+
config.gcp_location_id = 'us-central1'
|
401
|
+
config.gcp_project_id = 'my-gcp-project'
|
402
|
+
config.gcp_queue_prefix = 'my-app'
|
324
403
|
|
325
404
|
# Use your ngrok domain as the processor host
|
326
405
|
config.processor_host = 'https://your-tunnel-id.ngrok.io'
|
@@ -332,7 +411,7 @@ end
|
|
332
411
|
|
333
412
|
Finally start Rails to accept jobs from Google Cloud Tasks
|
334
413
|
```bash
|
335
|
-
rails s
|
414
|
+
bundle exec rails s
|
336
415
|
```
|
337
416
|
|
338
417
|
## Logging
|
@@ -341,7 +420,7 @@ There are several options available to configure logging and logging context.
|
|
341
420
|
### Configuring a logger
|
342
421
|
Cloudtasker uses `Rails.logger` if Rails is available and falls back on a plain ruby logger `Logger.new(STDOUT)` if not.
|
343
422
|
|
344
|
-
It is also possible to configure your own logger. For example you can setup Cloudtasker with [semantic_logger](http://rocketjob.github.io/semantic_logger) by doing the following your initializer:
|
423
|
+
It is also possible to configure your own logger. For example you can setup Cloudtasker with [semantic_logger](http://rocketjob.github.io/semantic_logger) by doing the following in your initializer:
|
345
424
|
```ruby
|
346
425
|
# config/initializers/cloudtasker.rb
|
347
426
|
|
@@ -387,7 +466,7 @@ Cloudtasker::WorkerLogger.log_context_processor = lambda { |worker|
|
|
387
466
|
}
|
388
467
|
```
|
389
468
|
|
390
|
-
You could also decide to log all available context
|
469
|
+
You could also decide to log all available context - including arguments passed to `perform` - for specific workers only:
|
391
470
|
```ruby
|
392
471
|
# app/workers/full_context_worker.rb
|
393
472
|
|
@@ -402,7 +481,7 @@ class FullContextWorker
|
|
402
481
|
end
|
403
482
|
```
|
404
483
|
|
405
|
-
See the [Cloudtasker::Worker class](
|
484
|
+
See the [Cloudtasker::Worker class](lib/cloudtasker/worker.rb) for more information on attributes available to be logged in your `log_context_processor` proc.
|
406
485
|
|
407
486
|
## Error Handling
|
408
487
|
|
@@ -534,7 +613,7 @@ MyWorker.new.perform({ 'foo' => 'bar', 'baz' => { 'key' => 'value' } })
|
|
534
613
|
```
|
535
614
|
|
536
615
|
### Be careful with default arguments
|
537
|
-
Default arguments passed to the `perform` method are not actually considered as job arguments. Default arguments will therefore be ignored in contextual logging and by extensions relying on arguments such as the
|
616
|
+
Default arguments passed to the `perform` method are not actually considered as job arguments. Default arguments will therefore be ignored in contextual logging and by extensions relying on arguments such as the [unique job](docs/UNIQUE_JOBS.md) extension.
|
538
617
|
|
539
618
|
Consider the following worker:
|
540
619
|
```ruby
|
@@ -556,7 +635,9 @@ If you enqueue this worker by omitting the second argument `MyWorker.perform_asy
|
|
556
635
|
- The `time_at` argument will be ignored by the `unique-job` extension, meaning that job uniqueness will be only based on the `user_id` argument.
|
557
636
|
|
558
637
|
### Handling big job payloads
|
559
|
-
|
638
|
+
Google Cloud Tasks enforces a limit of 100 KB for job payloads. Taking into accounts Cloudtasker authentication headers and meta information this leave ~85 KB of free space for JSONified job arguments.
|
639
|
+
|
640
|
+
Any excessive job payload (> 100 KB) will raise a `Cloudtasker::MaxTaskSizeExceededError`, both in production and development mode.
|
560
641
|
|
561
642
|
If you feel that a job payload is going to get big, prefer to store the payload using a datastore (e.g. Redis) and pass a reference to the job to retrieve the payload inside your job `perform` method.
|
562
643
|
|
@@ -585,6 +666,45 @@ Rails.cache.write(payload_id, data)
|
|
585
666
|
BigPayloadWorker.perform_async(payload_id)
|
586
667
|
```
|
587
668
|
|
669
|
+
### Sizing the concurrency of your queues
|
670
|
+
|
671
|
+
When defining the max concurrency of your queues (`max_concurrent_dispatches` in Cloud Tasks) you must keep in mind the maximum number of threads that your application provides. Otherwise your application threads may eventually get exhausted and your users will experience outages if all your web threads are busy running jobs.
|
672
|
+
|
673
|
+
#### With server based applications
|
674
|
+
|
675
|
+
Let's consider an application deployed in production with 3 instances, each having `RAILS_MAX_THREADS` set to `20`. This gives us a total of `60` threads available.
|
676
|
+
|
677
|
+
Now let's say that we distribute jobs across two queues: `default` and `critical`. We can set the concurrency of each queue depending on the profile of the application:
|
678
|
+
|
679
|
+
E.g. 1: The application serves requests from web users and runs backgrounds jobs in a balanced way
|
680
|
+
```
|
681
|
+
concurrency for default queue: 20
|
682
|
+
concurrency for critical queue: 10
|
683
|
+
|
684
|
+
Total threads consumed by jobs at most: 30
|
685
|
+
Total threads always available to web users at worst: 30
|
686
|
+
```
|
687
|
+
|
688
|
+
E.g. 2: The application is a micro-service API heavily focused on running jobs (e.g. data processing)
|
689
|
+
```
|
690
|
+
concurrency for default queue: 35
|
691
|
+
concurrency for critical queue: 15
|
692
|
+
|
693
|
+
Total threads consumed by jobs at most: 50
|
694
|
+
Total threads always available to API clients at worst: 10
|
695
|
+
```
|
696
|
+
|
697
|
+
Also always ensure that your total number of threads does not exceed the available number of database connections (if you use any).
|
698
|
+
|
699
|
+
#### With serverless applications
|
700
|
+
|
701
|
+
In a serverless context your application will be scaled up/down based on traffic. When we say 'traffic' this includes requests from Cloud Tasks to run jobs.
|
702
|
+
|
703
|
+
Because your application is auto-scaled - and assuming you haven't set a maximum - your job processing capacity if theoretically unlimited. The main limiting factor in a serverless context becomes external constraints such as the number of database connections available.
|
704
|
+
|
705
|
+
To size the concurrency of your queues you should therefore take the most limiting factor - which is often the database connection pool size of relational databases - and use the calculations of the previous section with this limiting factor as the capping parameter instead of threads.
|
706
|
+
|
707
|
+
|
588
708
|
## Development
|
589
709
|
|
590
710
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/_config.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
theme: jekyll-theme-slate
|
@@ -16,11 +16,6 @@ module Cloudtasker
|
|
16
16
|
# Run a worker from a Cloud Task payload
|
17
17
|
#
|
18
18
|
def run
|
19
|
-
# Build payload
|
20
|
-
payload = request.params
|
21
|
-
.slice(:worker, :job_id, :job_args, :job_meta)
|
22
|
-
.merge(job_retries: job_retries)
|
23
|
-
|
24
19
|
# Process payload
|
25
20
|
WorkerHandler.execute_from_payload!(payload)
|
26
21
|
head :no_content
|
@@ -39,6 +34,27 @@ module Cloudtasker
|
|
39
34
|
|
40
35
|
private
|
41
36
|
|
37
|
+
#
|
38
|
+
# Parse the request body and return the actual job
|
39
|
+
# payload.
|
40
|
+
#
|
41
|
+
# @return [Hash] The job payload
|
42
|
+
#
|
43
|
+
def payload
|
44
|
+
@payload ||= begin
|
45
|
+
# Get raw body
|
46
|
+
content = request.body.read
|
47
|
+
|
48
|
+
# Decode content if the body is Base64 encoded
|
49
|
+
if request.headers[Cloudtasker::Config::ENCODING_HEADER].to_s.downcase == 'base64'
|
50
|
+
content = Base64.decode64(content)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return content parsed as JSON and add job retries count
|
54
|
+
JSON.parse(content).merge(job_retries: job_retries)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
42
58
|
#
|
43
59
|
# Extract the number of times this task failed at runtime.
|
44
60
|
#
|
data/cloudtasker.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ['Arnaud Lachaume']
|
11
11
|
spec.email = ['arnaud.lachaume@keypup.io']
|
12
12
|
|
13
|
-
spec.summary = 'Background jobs for Ruby using Google Cloud Tasks (
|
14
|
-
spec.description = 'Background jobs for Ruby using Google Cloud Tasks (
|
13
|
+
spec.summary = 'Background jobs for Ruby using Google Cloud Tasks (beta)'
|
14
|
+
spec.description = 'Background jobs for Ruby using Google Cloud Tasks (beta)'
|
15
15
|
spec.homepage = 'https://github.com/keypup-io/cloudtasker'
|
16
16
|
spec.license = 'MIT'
|
17
17
|
|