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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00be8d2e572e3129ef5330cdbb555aa0485edd15b191d5d8ccc5d28a98a0eab8
4
- data.tar.gz: 79067d7953556f03e9a81ee9d977cf2734a9843df8f9a4613dbd8d81274bc599
3
+ metadata.gz: 96524dc4a6825a3760a462277f7b0a710d779521e759bce44374ea044dbd649d
4
+ data.tar.gz: 908f1497b7ad316549f4f347c363b183181f0e0a17a92bda3f50ac9c34e2247c
5
5
  SHA512:
6
- metadata.gz: 99d9b7ba99390e6bc10e9ed917262782a7c47814df6412c847dedd06a8a06a6b9ad4eaf5ddbcde03534ec88f34fcb1cda03621a3c2a0202031d087e6cd915c5f
7
- data.tar.gz: e15a6a167f15dbd8c390c7d393a80297b6cd805c85d4e5ca16f961ff147c909bebbfcf9c326708e7d7508caa3ff47b726f071e618e3979a1340848420311ddbb
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.rc6](https://github.com/keypup-io/cloudtasker/tree/v0.12.rc6) (2021-03-31)
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.rc6)
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
- - Redis: Use Redis Sets instead of key pattern matching for listing methods (Cron jobs and Local Server)
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
- redis.fetch(batch_state_gid)
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.write(batch_state_gid, jobs.map { |e| [e.job_id, 'scheduled'] }.to_h)
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
- redis.with_lock(batch_state_gid) do
235
- state = batch_state
236
- state[batch_id.to_sym] = status.to_s if state.key?(batch_id.to_sym)
237
- redis.write(batch_state_gid, state)
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 [<Type>] <description>
270
+ # @return [Boolean] True if the batch is complete.
245
271
  #
246
272
  def complete?
247
- redis.with_lock(batch_state_gid) do
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
- state.values.all? { |e| COMPLETION_STATUSES.include?(e) }
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
- # Capture batch state
335
- state = batch_state
360
+ migrate_batch_state_to_redis_hash
336
361
 
337
362
  # Delete child batches recursively
338
- state.to_h.keys.each { |id| self.class.find(id)&.cleanup }
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 worker has been enqueued)
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: LOCK_DURATION)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cloudtasker
4
- VERSION = '0.12.rc6'
4
+ VERSION = '0.12.rc7'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudtasker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.rc6
4
+ version: 0.12.rc7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arnaud Lachaume