cloudtasker 0.12.rc6 → 0.12.rc7
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/CHANGELOG.md +5 -3
- data/lib/cloudtasker/batch/job.rb +42 -17
- data/lib/cloudtasker/redis_client.rb +6 -2
- data/lib/cloudtasker/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96524dc4a6825a3760a462277f7b0a710d779521e759bce44374ea044dbd649d
|
|
4
|
+
data.tar.gz: 908f1497b7ad316549f4f347c363b183181f0e0a17a92bda3f50ac9c34e2247c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e18579d27321e09f1e997ad3fdd3e3e0d1d0c344cd5fc553b64f665937fbe510cd11957381eee1fee5c100e2f14d8390434f26c60307fec4ecf4a681b15885d8
|
|
7
|
+
data.tar.gz: 3b688838f1a518f2f5c7b914a590f035d8a828c2c2b67838173a1712b8765e2ce34cddb8ddf1214aaefc26ce8ec43b7cc1dbe4eb450ccb24feb9e06bcd19bac7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## Latest RC [v0.12.
|
|
3
|
+
## Latest RC [v0.12.rc7](https://github.com/keypup-io/cloudtasker/tree/v0.12.rc7) (2021-03-31)
|
|
4
4
|
|
|
5
|
-
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.11.0...v0.12.
|
|
5
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.11.0...v0.12.rc7)
|
|
6
6
|
|
|
7
7
|
**Improvements:**
|
|
8
8
|
- ActiveJob: do not double log errors (ActiveJob has its own error logging)
|
|
9
|
+
- Cron jobs: Use Redis Sets instead of key pattern matching for resource listing
|
|
9
10
|
- Error logging: Use worker logger so as to include context (job args etc.)
|
|
10
11
|
- Error logging: Do not log exception and stack trace separately, combine them instead.
|
|
11
12
|
- Batch callbacks: Retry jobs when completion callback fails
|
|
12
|
-
-
|
|
13
|
+
- Batch state: use native Redis hashes to store batch state instead of a serialized hash in a string key
|
|
13
14
|
- 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.
|
|
15
|
+
- Local server: Use Redis Sets instead of key pattern matching for resource listing
|
|
14
16
|
- Worker: raise DeadWorkerError instead of MissingWorkerArgumentsError when arguments are missing. This is more consistent with what middlewares expect.
|
|
15
17
|
|
|
16
18
|
**Fixed bugs:**
|
|
@@ -17,6 +17,10 @@ module Cloudtasker
|
|
|
17
17
|
# because the jobs will be either retried or dropped
|
|
18
18
|
IGNORED_ERRORED_CALLBACKS = %i[on_child_error on_child_dead].freeze
|
|
19
19
|
|
|
20
|
+
# The maximum number of seconds to wait for a batch state lock
|
|
21
|
+
# to be acquired.
|
|
22
|
+
BATCH_MAX_LOCK_WAIT = 60
|
|
23
|
+
|
|
20
24
|
#
|
|
21
25
|
# Return the cloudtasker redis client
|
|
22
26
|
#
|
|
@@ -176,7 +180,9 @@ module Cloudtasker
|
|
|
176
180
|
# @return [Hash] The state of each child worker.
|
|
177
181
|
#
|
|
178
182
|
def batch_state
|
|
179
|
-
|
|
183
|
+
migrate_batch_state_to_redis_hash
|
|
184
|
+
|
|
185
|
+
redis.hgetall(batch_state_gid)
|
|
180
186
|
end
|
|
181
187
|
|
|
182
188
|
#
|
|
@@ -208,6 +214,24 @@ module Cloudtasker
|
|
|
208
214
|
)
|
|
209
215
|
end
|
|
210
216
|
|
|
217
|
+
#
|
|
218
|
+
# This method migrates the batch state to be a Redis hash instead
|
|
219
|
+
# of a hash stored in a string key.
|
|
220
|
+
#
|
|
221
|
+
def migrate_batch_state_to_redis_hash
|
|
222
|
+
return unless redis.type(batch_state_gid) == 'string'
|
|
223
|
+
|
|
224
|
+
# Migrate batch state to Redis hash if it is still using a legacy string key
|
|
225
|
+
# We acquire a lock then check again
|
|
226
|
+
redis.with_lock(batch_state_gid, max_wait: BATCH_MAX_LOCK_WAIT) do
|
|
227
|
+
if redis.type(batch_state_gid) == 'string'
|
|
228
|
+
state = redis.fetch(batch_state_gid)
|
|
229
|
+
redis.del(batch_state_gid)
|
|
230
|
+
redis.hset(batch_state_gid, state) if state.any?
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
211
235
|
#
|
|
212
236
|
# Save the batch.
|
|
213
237
|
#
|
|
@@ -218,8 +242,11 @@ module Cloudtasker
|
|
|
218
242
|
# complete (success or failure).
|
|
219
243
|
redis.write(batch_gid, worker.to_h)
|
|
220
244
|
|
|
245
|
+
# Stop there if no jobs to save
|
|
246
|
+
return if jobs.empty?
|
|
247
|
+
|
|
221
248
|
# Save list of child workers
|
|
222
|
-
redis.
|
|
249
|
+
redis.hset(batch_state_gid, jobs.map { |e| [e.job_id, 'scheduled'] }.to_h)
|
|
223
250
|
end
|
|
224
251
|
|
|
225
252
|
#
|
|
@@ -228,28 +255,27 @@ module Cloudtasker
|
|
|
228
255
|
# @param [String] job_id The batch id.
|
|
229
256
|
# @param [String] status The status of the sub-batch.
|
|
230
257
|
#
|
|
231
|
-
# @return [<Type>] <description>
|
|
232
|
-
#
|
|
233
258
|
def update_state(batch_id, status)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
259
|
+
migrate_batch_state_to_redis_hash
|
|
260
|
+
|
|
261
|
+
# 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)
|
|
238
264
|
end
|
|
239
265
|
end
|
|
240
266
|
|
|
241
267
|
#
|
|
242
268
|
# Return true if all the child workers have completed.
|
|
243
269
|
#
|
|
244
|
-
# @return [
|
|
270
|
+
# @return [Boolean] True if the batch is complete.
|
|
245
271
|
#
|
|
246
272
|
def complete?
|
|
247
|
-
|
|
248
|
-
state = redis.fetch(batch_state_gid)
|
|
249
|
-
return true unless state
|
|
273
|
+
migrate_batch_state_to_redis_hash
|
|
250
274
|
|
|
275
|
+
# Check that all child jobs have completed
|
|
276
|
+
redis.with_lock(batch_state_gid, max_wait: BATCH_MAX_LOCK_WAIT) do
|
|
251
277
|
# Check that all children are complete
|
|
252
|
-
|
|
278
|
+
redis.hvals(batch_state_gid).all? { |e| COMPLETION_STATUSES.include?(e) }
|
|
253
279
|
end
|
|
254
280
|
end
|
|
255
281
|
|
|
@@ -331,11 +357,10 @@ module Cloudtasker
|
|
|
331
357
|
# Remove all batch and sub-batch keys from Redis.
|
|
332
358
|
#
|
|
333
359
|
def cleanup
|
|
334
|
-
|
|
335
|
-
state = batch_state
|
|
360
|
+
migrate_batch_state_to_redis_hash
|
|
336
361
|
|
|
337
362
|
# Delete child batches recursively
|
|
338
|
-
|
|
363
|
+
redis.hkeys(batch_state_gid).each { |id| self.class.find(id)&.cleanup }
|
|
339
364
|
|
|
340
365
|
# Delete batch redis entries
|
|
341
366
|
redis.del(batch_gid)
|
|
@@ -402,7 +427,7 @@ module Cloudtasker
|
|
|
402
427
|
# Perform job
|
|
403
428
|
yield
|
|
404
429
|
|
|
405
|
-
# Save batch (if child
|
|
430
|
+
# Save batch (if child workers have been enqueued)
|
|
406
431
|
setup
|
|
407
432
|
|
|
408
433
|
# Complete batch
|
|
@@ -75,14 +75,18 @@ module Cloudtasker
|
|
|
75
75
|
# end
|
|
76
76
|
#
|
|
77
77
|
# @param [String] cache_key The cache key to access.
|
|
78
|
+
# @param [Integer] max_wait The number of seconds after which the lock will be cleared anyway.
|
|
78
79
|
#
|
|
79
|
-
def with_lock(cache_key)
|
|
80
|
+
def with_lock(cache_key, max_wait: nil)
|
|
80
81
|
return nil unless cache_key
|
|
81
82
|
|
|
83
|
+
# Set max wait
|
|
84
|
+
max_wait = (max_wait || LOCK_DURATION).to_i
|
|
85
|
+
|
|
82
86
|
# Wait to acquire lock
|
|
83
87
|
lock_key = [LOCK_KEY_PREFIX, cache_key].join('/')
|
|
84
88
|
client.with do |conn|
|
|
85
|
-
sleep(LOCK_WAIT_DURATION) until conn.set(lock_key, true, nx: true, ex:
|
|
89
|
+
sleep(LOCK_WAIT_DURATION) until conn.set(lock_key, true, nx: true, ex: max_wait)
|
|
86
90
|
end
|
|
87
91
|
|
|
88
92
|
# yield content
|
data/lib/cloudtasker/version.rb
CHANGED