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

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: 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