cloudtasker 0.12.rc9 → 0.12.rc10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50cd6021ad7511d7b5b385a6086eb315d9381a4f43909a6e1e9a0defbc679ea4
4
- data.tar.gz: dc16cc1330b14b46a5d6ade9f9c171981fd3aef5b3db67dd474e29548acc177f
3
+ metadata.gz: 5763bef46a0c554549150326375c3fb49c9eb77193b6862334dc1da72a5fe34f
4
+ data.tar.gz: 211272f9129642cb8c7260f639a6a76714161ac37c87dc5f073633a072781b44
5
5
  SHA512:
6
- metadata.gz: 30feac9331b9e8113e71af6c44a20d2f47fcbd41652a0d345ab8808d272bd14271ebb4a98711e42b238f6202fa8023a37c543e0f4ec7d9f9f7a46cc2732d96aa
7
- data.tar.gz: 9b70a3c0733b2c510fafe48232c65bb79f5ad4da6b90fbcff86c0736fee590fab5f89846df9c41855dc7084460425660ee42799975975775b2239b9b8997171a
6
+ metadata.gz: ac4012191c2878256abdc446eabc4cd4cf4ff822e426fc7a89e25c77ab2724c5b1d2e508fb88092ddde86680512797c50711d4188798a281cf275b3e03304a0e
7
+ data.tar.gz: 7a1558eed571862501a3e5a264cfa006014e9454c0f31cb915c9d5229aed6a9c47f539287cb447a226db4302b60d761496256791d9844cc8291164910ec8d6f5
data/CHANGELOG.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Changelog
2
2
 
3
- ## Latest RC [v0.12.rc8](https://github.com/keypup-io/cloudtasker/tree/v0.12.rc8) (2021-04-06)
3
+ ## Latest RC [v0.12.rc10](https://github.com/keypup-io/cloudtasker/tree/v0.12.rc10) (2021-05-31)
4
4
 
5
- [Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.11.0...v0.12.rc8)
5
+ [Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.11.0...v0.12.rc10)
6
6
 
7
7
  **Improvements:**
8
8
  - ActiveJob: do not double log errors (ActiveJob has its own error logging)
@@ -10,11 +10,14 @@
10
10
  - Batch state: use native Redis hashes to store batch state instead of a serialized hash in a string key
11
11
  - Batch progress: restrict calculation to direct children by default. Allow depth to be specified. Calculating progress using all tree jobs created significant delays on large batches.
12
12
  - Batch redis usage: cleanup batches as they get completed or become dead to avoid excessive redis usage with large batches.
13
+ - Batch expansion: Inject `parent_batch` in jobs. Can be used to expand the parent batch the job is in.
13
14
  - Configuration: allow configuration of Cloud Tasks `dispatch deadline` at global and worker level
14
15
  - Cron jobs: Use Redis Sets instead of key pattern matching for resource listing
15
16
  - Error logging: Use worker logger so as to include context (job args etc.)
16
17
  - Error logging: Do not log exception and stack trace separately, combine them instead.
17
18
  - Local server: Use Redis Sets instead of key pattern matching for resource listing
19
+ - Local server: Guard against nil tasks to prevent job daemon failures
20
+ - Performance: remove use of redis locks and rely on atomic transactions instead for Batch and Unique Job.
18
21
  - Worker: raise DeadWorkerError instead of MissingWorkerArgumentsError when arguments are missing. This is more consistent with what middlewares expect.
19
22
  - Worker redis usage: delete redis payload storage once the job is successful or dead instead of expiring the key.
20
23
 
data/docs/BATCH_JOBS.md CHANGED
@@ -18,7 +18,7 @@ Cloudtasker.configure do |config|
18
18
  end
19
19
  ```
20
20
 
21
- ## Example
21
+ ## Example: Creating a new batch
22
22
 
23
23
  The following example defines a worker that adds itself to the batch with different arguments then monitors the success of the batch.
24
24
 
@@ -47,6 +47,38 @@ class BatchWorker
47
47
  end
48
48
  ```
49
49
 
50
+ ## Example: Expanding the parent batch
51
+ **Note**: `parent_batch` is available since `0.12.rc10`
52
+
53
+ ```ruby
54
+ # All the jobs will be attached to the top parent batch.
55
+ class BatchWorker
56
+ include Cloudtasker::Worker
57
+
58
+ def perform(level, instance)
59
+ # Use existing parent_batch or create a new one
60
+ current_batch = parent_batch || batch
61
+
62
+ 3.times { |n| current_batch.add(self.class, level + 1, n) } if level < 2
63
+ end
64
+
65
+ # Invoked when any descendant (e.g. sub-sub job) is complete
66
+ def on_batch_node_complete(child)
67
+ logger.info("Direct or Indirect child complete: #{child.job_id}")
68
+ end
69
+
70
+ # Invoked when a direct descendant is complete
71
+ def on_child_complete(child)
72
+ logger.info("Direct child complete: #{child.job_id}")
73
+ end
74
+
75
+ # Invoked when all chidren have finished
76
+ def on_batch_complete
77
+ Rails.logger.info("Batch complete")
78
+ end
79
+ end
80
+ ```
81
+
50
82
  ## Available callbacks
51
83
 
52
84
  The following callbacks are available on your workers to track the progress of the batch:
@@ -39,7 +39,7 @@ module Cloudtasker
39
39
  def self.all
40
40
  if redis.exists?(key)
41
41
  # Use Schedule Set if available
42
- redis.smembers(key).map { |id| find(id) }
42
+ redis.smembers(key).map { |id| find(id) }.compact
43
43
  else
44
44
  # Fallback to redis key matching and migrate tasks
45
45
  # to use Task Set instead.
@@ -6,7 +6,7 @@ module Cloudtasker
6
6
  # Include batch related methods onto Cloudtasker::Worker
7
7
  # See: Cloudtasker::Batch::Middleware#configure
8
8
  module Worker
9
- attr_accessor :batch
9
+ attr_accessor :batch, :parent_batch
10
10
  end
11
11
  end
12
12
  end
@@ -73,8 +73,12 @@ module Cloudtasker
73
73
  # Load extension if not loaded already on the worker class
74
74
  worker.class.include(Extension::Worker) unless worker.class <= Extension::Worker
75
75
 
76
- # Add batch capability
76
+ # Add batch and parent batch to worker
77
77
  worker.batch = new(worker)
78
+ worker.parent_batch = worker.batch.parent_batch
79
+
80
+ # Return the batch
81
+ worker.batch
78
82
  end
79
83
 
80
84
  #
@@ -259,9 +263,7 @@ module Cloudtasker
259
263
  migrate_batch_state_to_redis_hash
260
264
 
261
265
  # Update the batch state batch_id entry with the new status
262
- redis.with_lock("#{batch_state_gid}/#{batch_id}", max_wait: BATCH_MAX_LOCK_WAIT) do
263
- redis.hset(batch_state_gid, batch_id, status) if redis.hexists(batch_state_gid, batch_id)
264
- end
266
+ redis.hset(batch_state_gid, batch_id, status) if redis.hexists(batch_state_gid, batch_id)
265
267
  end
266
268
 
267
269
  #
@@ -273,10 +275,7 @@ module Cloudtasker
273
275
  migrate_batch_state_to_redis_hash
274
276
 
275
277
  # Check that all child jobs have completed
276
- redis.with_lock(batch_state_gid, max_wait: BATCH_MAX_LOCK_WAIT) do
277
- # Check that all children are complete
278
- redis.hvals(batch_state_gid).all? { |e| COMPLETION_STATUSES.include?(e) }
279
- end
278
+ redis.hvals(batch_state_gid).all? { |e| COMPLETION_STATUSES.include?(e) }
280
279
  end
281
280
 
282
281
  #
@@ -427,8 +426,11 @@ module Cloudtasker
427
426
  # Perform job
428
427
  yield
429
428
 
430
- # Save batch (if child workers have been enqueued)
431
- setup
429
+ # Save batch if child jobs added
430
+ setup if jobs.any?
431
+
432
+ # Save parent batch if batch expanded
433
+ parent_batch&.setup if parent_batch&.jobs&.any?
432
434
 
433
435
  # Complete batch
434
436
  complete(:completed)
@@ -84,7 +84,7 @@ module Cloudtasker
84
84
 
85
85
  # Deliver task
86
86
  begin
87
- Thread.current['task'].deliver
87
+ Thread.current['task']&.deliver
88
88
  rescue Errno::EBADF, Errno::ECONNREFUSED => e
89
89
  raise(e) unless Thread.current['attempts'] < 3
90
90
 
@@ -149,25 +149,18 @@ module Cloudtasker
149
149
  # if taken by another job.
150
150
  #
151
151
  def lock!
152
- redis.with_lock(unique_gid) do
153
- locked_id = redis.get(unique_gid)
152
+ lock_acquired = redis.set(unique_gid, id, nx: true, ex: lock_ttl)
153
+ lock_already_acquired = !lock_acquired && redis.get(unique_gid) == id
154
154
 
155
- # Abort job lock process if lock is already taken by another job
156
- raise(LockError, locked_id) if locked_id && locked_id != id
157
-
158
- # Take job lock if the lock is currently free
159
- redis.set(unique_gid, id, ex: lock_ttl) unless locked_id
160
- end
155
+ raise(LockError) unless lock_acquired || lock_already_acquired
161
156
  end
162
157
 
163
158
  #
164
159
  # Delete the job lock.
165
160
  #
166
161
  def unlock!
167
- redis.with_lock(unique_gid) do
168
- locked_id = redis.get(unique_gid)
169
- redis.del(unique_gid) if locked_id == id
170
- end
162
+ locked_id = redis.get(unique_gid)
163
+ redis.del(unique_gid) if locked_id == id
171
164
  end
172
165
  end
173
166
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cloudtasker
4
- VERSION = '0.12.rc9'
4
+ VERSION = '0.12.rc10'
5
5
  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.12.rc9
4
+ version: 0.12.rc10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arnaud Lachaume
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-19 00:00:00.000000000 Z
11
+ date: 2021-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport