distributed-lock-google-cloud-storage 1.0.0 → 1.1.0

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: 6262a932fc426a59ec6e6e4515fb925d282e04eb972fd78eb75daa0a81602a98
4
- data.tar.gz: 408ae99f1f70e1e13a3f7bd9ee37384291e85dccc933b167259e3863a669043d
3
+ metadata.gz: 2ba7bdb482b1bf1a10c8c3933ff8680d980099de2c66fd8cf0f1aac0db7c258d
4
+ data.tar.gz: 4597cc7ffd7ae791808eb677c875b62f19d48bcd8ff83c63a38a2f4683ec2829
5
5
  SHA512:
6
- metadata.gz: d6d47baecddc7660d441c1ef72b9a33337d5763b90e3f7b85a22499ecd3bd2ac2b82649175e36d0e15b38c89bc45722334716d512c8c34e1947cffc72fd7a7f2
7
- data.tar.gz: 4abf33f73e4a443a6c93fdcecabe0f7efefccbcea7d56fd448a9448596d8834b93850963c5b39a1a97a9557fead5bb0c9fcd3e807d56a67a37d1d8f545fa5896
6
+ metadata.gz: 323019ce82a1dda8252a9332dca0e024f5801ec5367320ad7e2133712cc55e35060f9fc2fb1bed1545dbfe333477b1498a2e410f4a77551d993ae7838e6f67eb
7
+ data.tar.gz: 2b7d1b8ff59ddfdd14d100fdd67420e57b54c2c87688ccfbbceff53c6b22561630e1f7c2a5803bb9329650f818134b514d5238264251af944024950a6260047c
@@ -11,6 +11,7 @@ require_relative 'utils'
11
11
  module DistributedLock
12
12
  module GoogleCloudStorage
13
13
  class Lock
14
+ # @!visibility private
14
15
  DEFAULT_INSTANCE_IDENTITY_PREFIX_WITHOUT_PID = SecureRandom.hex(12).freeze
15
16
 
16
17
  include Utils
@@ -65,13 +66,13 @@ module DistributedLock
65
66
  # when acquiring the lock fails. Must be at least 0.
66
67
  # @param object_acl [String, nil] A predefined set of access control to apply to the Cloud Storage
67
68
  # object. See the `acl` parameter in
68
- # [https://googleapis.dev/ruby/google-cloud-storage/latest/Google/Cloud/Storage/Bucket.html#create_file-instance_method](Google::Cloud::Storage::Bucket#create_file)
69
+ # [Google::Cloud::Storage::Bucket#create_file](https://googleapis.dev/ruby/google-cloud-storage/latest/Google/Cloud/Storage/Bucket.html#create_file-instance_method)
69
70
  # for acceptable values.
70
71
  # @param cloud_storage_options [Hash, nil] Additional options to pass to
71
- # {https://googleapis.dev/ruby/google-cloud-storage/latest/Google/Cloud/Storage.html#new-class_method Google::Cloud::Storage.new}.
72
+ # [Google::Cloud::Storage.new](https://googleapis.dev/ruby/google-cloud-storage/latest/Google/Cloud/Storage.html#new-class_method).
72
73
  # See its documentation to learn which options are available.
73
74
  # @param cloud_storage_bucket_options [Hash, nil] Additional options to pass to
74
- # {https://googleapis.dev/ruby/google-cloud-storage/latest/Google/Cloud/Storage/Project.html#bucket-instance_method Google::Cloud::Storage::Project#bucket}.
75
+ # [Google::Cloud::Storage::Project#bucket](https://googleapis.dev/ruby/google-cloud-storage/latest/Google/Cloud/Storage/Project.html#bucket-instance_method).
75
76
  # See its documentation to learn which options are available.
76
77
  #
77
78
  # @note The logger must either be thread-safe, or all writes to this logger by anything besides
@@ -119,6 +120,7 @@ module DistributedLock
119
120
  @owner = nil
120
121
  @metageneration = nil
121
122
  @refresher_thread = nil
123
+ @refresher_error = nil
122
124
 
123
125
  # The refresher generation is incremented every time we shutdown
124
126
  # the refresher thread. It allows the refresher thread to know
@@ -256,7 +258,7 @@ module DistributedLock
256
258
  # obtained by some other instance identity, waits until it becomes available,
257
259
  # or until timeout.
258
260
  #
259
- # Accepts the same parameters as #lock.
261
+ # Accepts the same parameters as {#lock}.
260
262
  #
261
263
  # @return The block's return value.
262
264
  # @raise [AlreadyLockedError] This Lock instance — according to its internal state — believes
@@ -273,10 +275,10 @@ module DistributedLock
273
275
 
274
276
  # Pretends like we've never obtained this lock, abandoning our internal state about the lock.
275
277
  #
276
- # Shuts down background lock refreshing, and ensures that
277
- # #locked_according_to_internal_state? returns false.
278
+ # Shuts down background lock refreshing, and ensures that {#locked_according_to_internal_state?}
279
+ # returns false.
278
280
  #
279
- # Does not modify any server data, so #locked_according_to_server? may still return true.
281
+ # Does not modify any server data, so {#locked_according_to_server?} may still return true.
280
282
  #
281
283
  # @return [void]
282
284
  def abandon
@@ -302,15 +304,19 @@ module DistributedLock
302
304
  # Returns whether the lock is healthy. A lock is considered healthy until
303
305
  # we fail to refresh the lock too many times consecutively.
304
306
  #
305
- # Failure to refresh could happen for many reasons, including but not limited
306
- # to: network problems, the lock object being forcefully deleted by someone else.
307
+ # Failure to refresh could happen for many reasons. Some failures are temporary, such
308
+ # as network problems. Others are permanent, such as the lock object being forcefully
309
+ # deleted by someone else.
307
310
  #
308
- # "Too many" is defined by the `max_refresh_fails` argument passed to the constructor.
311
+ # Upon encountering a permanent failure, the lock is immediately declared unhealthy.
312
+ # Upon encountering a temporary failure, the lock is declared unhealthy after encountering
313
+ # a temporary error `max_refresh_fails` times consecutively.
309
314
  #
310
315
  # It only makes sense to call this method after having obtained this lock.
311
316
  #
312
317
  # @return [Boolean]
313
318
  # @raise [NotLockedError] This lock was not obtained.
319
+ # @see #last_refresh_error
314
320
  def healthy?
315
321
  @state_mutex.synchronize do
316
322
  raise NotLockedError, 'Not locked' if !unsynced_locked_according_to_internal_state?
@@ -318,7 +324,9 @@ module DistributedLock
318
324
  end
319
325
  end
320
326
 
321
- # Checks whether the lock is healthy. See #healthy? for the definition of "healthy".
327
+ # Checks whether the lock is healthy. See {#healthy?} for the definition of "healthy".
328
+ # Use {#last_refresh_error} to query the last error that caused the lock to be declared
329
+ # unhealthy.
322
330
  #
323
331
  # It only makes sense to call this method after having obtained this lock.
324
332
  #
@@ -329,6 +337,19 @@ module DistributedLock
329
337
  raise LockUnhealthyError, 'Lock is not healthy' if !healthy?
330
338
  end
331
339
 
340
+ # Returns the last error that caused the lock to be declared unhealthy.
341
+ #
342
+ # Don't use this method to check whether the lock is _currently_ healthy.
343
+ # If this lock has ever been unhealthy, then this method returns a non-nil value
344
+ # even if the lock is currently healthy.
345
+ #
346
+ # @return [StandardError, nil]
347
+ def last_refresh_error
348
+ @state_mutex.synchronize do
349
+ @refresher_error
350
+ end
351
+ end
352
+
332
353
 
333
354
  private
334
355
 
@@ -429,9 +450,7 @@ module DistributedLock
429
450
  def delete_lock_object(expected_metageneration)
430
451
  file = @bucket.file(@path, skip_lookup: true)
431
452
  file.delete(if_metageneration_match: expected_metageneration)
432
- rescue Google::Cloud::NotFoundError
433
- false
434
- rescue Google::Cloud::FailedPreconditionError
453
+ rescue Google::Cloud::NotFoundError, Google::Cloud::FailedPreconditionError
435
454
  false
436
455
  end
437
456
 
@@ -563,7 +582,17 @@ module DistributedLock
563
582
  end
564
583
  log_debug { "Done refreshing lock. metageneration=#{file.metageneration}" }
565
584
  true
585
+
566
586
  rescue => e
587
+ @state_mutex.synchronize do
588
+ if @refresher_generation != refresher_generation
589
+ log_debug { 'Abort refreshing lock' }
590
+ return true
591
+ end
592
+
593
+ @refresher_error = e
594
+ end
595
+
567
596
  log_error { "Error refreshing lock: #{e}" }
568
597
  [false, permanent_failure]
569
598
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module DistributedLock
4
4
  module GoogleCloudStorage
5
+ # @!visibility private
5
6
  module Utils
6
7
  private
7
8
 
@@ -3,7 +3,7 @@
3
3
  module DistributedLock
4
4
  module GoogleCloudStorage
5
5
  module Version
6
- VERSION_STRING = '1.0.0'
6
+ VERSION_STRING = '1.1.0'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: distributed-lock-google-cloud-storage
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hongli Lai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-09 00:00:00.000000000 Z
11
+ date: 2021-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-cloud-storage