redis_queued_locks 1.4.0 → 1.6.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: 448f8b89e4a34bb2543b55d46877d80f76cf8e4b5d07735486f53eb1edb37432
4
- data.tar.gz: 4fbefadd9a162ab298b100bca38387045c65c89918ffd70c3f4aa418aa72d22a
3
+ metadata.gz: dd9e0ee49d4c08d6ba572a825da792468926b2f676e872a2337b1ce2eff60836
4
+ data.tar.gz: ae635ac450f966539581c4b5a53098b92ba29562bb0641049571ca0ceb1461e7
5
5
  SHA512:
6
- metadata.gz: 738c503d6189ca4673d1bc5af829066378654a070b78691ae7d1001e832795dbb91f1cde3e89252ff6b9831a659daf517eea1ea2ab721101c9140afe16b44974
7
- data.tar.gz: cb2b4893238e55688b01c56f5f0004217d206122d5ae5ef3a0ea8f2d206323442e4c10bf78f3d504f947795864decc712f5385448b205151ccfe7ca39ab9ea0a
6
+ metadata.gz: b678b3fbccd5273d17d07120c144b0eb1c6be32db73ff1aa2f9fb19f485d30499645f3c4592fad0cb4cdeab1ebcd37f437b62740e01a46dce999eaaa2814f146
7
+ data.tar.gz: b8cb79c79767cd1d3b831992454c84c8399f6bf7ac313b8a2d0a7527711f555cb2196a172ae435103df2fc4c3e483b0a5b35775fba4baee7b7bad6234103cb0a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.6.0] - 2024-05-25
4
+ ### Added
5
+ - New Feature: **Instrumentation Sampling** - configurable instrumentation sampling based on `weight` algorithm (where the weight is a percentage of RQL cases that should be logged);
6
+ - Missing instrumenter customization in public `RedisQueuedLocks::Client` methods;
7
+ - Documentation updates;
8
+
9
+ ## [1.5.0] - 2024-05-23
10
+ ### Added
11
+ - New Feature: **Log sampling** - configurable log sampling based on `weight` algorithm (where the weight is a percentage of RQL cases that should be logged);
12
+
3
13
  ## [1.4.0] - 2024-05-13
4
14
  ### Added
5
15
  - `#lock`/`#lock!`: reduced memory allocaiton during `:meta` attribute type checking;
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Each lock request is put into the request queue (each lock is hosted by it's own queue separately from other queues) and processed in order of their priority (FIFO). Each lock request lives some period of time (RTTL) (with requeue capabilities) which guarantees the request queue will never be stacked.
6
6
 
7
- Provides flexible invocation flow, parametrized limits (lock request ttl, lock ttls, queue ttls, lock attempts limit, fast failing, etc), logging and instrumentation.
7
+ Provides flexible invocation flow, parametrized limits (lock request ttl, lock ttl, queue ttl, lock attempts limit, fast failing, etc), logging and instrumentation.
8
8
 
9
9
  ---
10
10
 
@@ -182,10 +182,10 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
182
182
 
183
183
  # (default: RedisQueuedLocks::Instrument::VoidNotifier)
184
184
  # - instrumentation layer;
185
- # - you can provde your own instrumenter with `#notify(event, payload = {})`
185
+ # - you can provide your own instrumenter that should realize `#notify(event, payload = {})` interface:
186
186
  # - event: <string> requried;
187
187
  # - payload: <hash> requried;
188
- # - disabled by default via VoidNotifier;
188
+ # - disabled by default via `VoidNotifier`;
189
189
  config.instrumenter = RedisQueuedLocks::Instrument::ActiveSupport
190
190
 
191
191
  # (default: -> { RedisQueuedLocks::Resource.calc_uniq_identity })
@@ -232,6 +232,48 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
232
232
  # - "[redis_queued_locks.try_lock.exit__lock_still_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "first_acq_id_in_queue", "locked_by_acq_id", "<current_lock_data>");
233
233
  # - "[redis_queued_locks.try_lock.obtain__free_to_acquire]" (logs "lock_key", "queue_ttl", "acq_id");
234
234
  config.log_lock_try = false
235
+
236
+ # (default: false)
237
+ # - enables <log sampling>: only the configured percent of RQL cases will be logged;
238
+ # - disabled by default;
239
+ # - works in tandem with <config.log_sampling_percent> and <log.sampler> configs;
240
+ config.log_sampling_enabled = false
241
+
242
+ # (default: 15)
243
+ # - the percent of cases that should be logged;
244
+ # - take an effect when <config.log_sampling_enalbed> is true;
245
+ # - works in tandem with <config.log_sampling_enabled> and <config.log_sampler> configs;
246
+ config.log_sampling_percent = 15
247
+
248
+ # (default: RedisQueuedLocks::Logging::Sampler)
249
+ # - percent-based log sampler that decides should be RQL case logged or not;
250
+ # - works in tandem with <config.log_sampling_enabled> and <config.log_sampling_percent> configs;
251
+ # - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
252
+ # method so the algorithm error is ~(0%..13%);
253
+ # - you can provide your own log sampler with bettter algorithm that should realize
254
+ # `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
255
+ config.log_sampler = RedisQueuedLocks::Logging::Sampler
256
+
257
+ # (default: false)
258
+ # - enables <instrumentaion sampling>: only the configured percent of RQL cases will be instrumented;
259
+ # - disabled by default;
260
+ # - works in tandem with <config.instr_sampling_percent and <log.instr_sampler>;
261
+ config.instr_sampling_enabled = false
262
+
263
+ # (default: 15)
264
+ # - the percent of cases that should be instrumented;
265
+ # - take an effect when <config.instr_sampling_enalbed> is true;
266
+ # - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampler> configs;
267
+ config.instr_sampling_percent = 15
268
+
269
+ # (default: RedisQueuedLocks::Instrument::Sampler)
270
+ # - percent-based log sampler that decides should be RQL case instrumented or not;
271
+ # - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampling_percent> configs;
272
+ # - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
273
+ # method so the algorithm error is ~(0%..13%);
274
+ # - you can provide your own log sampler with bettter algorithm that should realize
275
+ # `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
276
+ config.instr_sampler = RedisQueuedLocks::Instrument::Sampler
235
277
  end
236
278
  ```
237
279
 
@@ -288,8 +330,15 @@ def lock(
288
330
  identity: uniq_identity, # (attr_accessor) calculated during client instantiation via config[:uniq_identifier] proc;
289
331
  meta: nil,
290
332
  instrument: nil,
333
+ instrumenter: config[:instrumenter],
291
334
  logger: config[:logger],
292
335
  log_lock_try: config[:log_lock_try],
336
+ log_sampling_enabled: config[:log_sampling_enabled],
337
+ log_sampling_percent: config[:log_sampling_percent],
338
+ log_sampler: config[:log_sampler],
339
+ instr_sampling_enabled: config[:instr_sampling_enabled],
340
+ instr_sampling_percent: config[:instr_sampling_percent],
341
+ instr_sampler: config[:instr_sampler],
293
342
  &block
294
343
  )
295
344
  ```
@@ -322,6 +371,9 @@ def lock(
322
371
  - See RedisQueuedLocks::Instrument::ActiveSupport for example;
323
372
  - See [Instrumentation](#instrumentation) section of docs;
324
373
  - pre-configured in `config[:isntrumenter]` with void notifier (`RedisQueuedLocks::Instrumenter::VoidNotifier`);
374
+ - `instrument` - (optional) `[NilClass,Any]`
375
+ - Custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
376
+ - `nil` by default (means "no custom instrumentation data");
325
377
  - `raise_errors` - (optional) `[Boolean]`
326
378
  - Raise errors on library-related limits (such as timeout or retry count limit) and on lock conflicts (such as same-process dead locks);
327
379
  - `false` by default;
@@ -353,9 +405,6 @@ def lock(
353
405
  - A custom metadata wich will be passed to the lock data in addition to the existing data;
354
406
  - Custom metadata can not contain reserved lock data keys (such as `lock_key`, `acq_id`, `ts`, `ini_ttl`, `rem_ttl`);
355
407
  - `nil` by default (means "no metadata");
356
- - `instrument` - (optional) `[NilClass,Any]`
357
- - Custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
358
- - `nil` by default (means "no custom instrumentation data");
359
408
  - `logger` - (optional) `[::Logger,#debug]`
360
409
  - Logger object used for loggin internal mutation oeprations and opertioan results / process progress;
361
410
  - pre-configured in `config[:logger]` with void logger `RedisQueuedLocks::Logging::VoidLogger`;
@@ -363,6 +412,42 @@ def lock(
363
412
  - should be logged the each try of lock acquiring (a lot of logs can be generated depending on your retry configurations);
364
413
  - pre-configured in `config[:log_lock_try]`;
365
414
  - `false` by default;
415
+ - `log_sampling_enabled` - (optional) `[Boolean]`
416
+ - enables **log sampling**: only the configured percent of RQL cases will be logged;
417
+ - disabled by default;
418
+ - works in tandem with `log_sampling_percent` and `log_sampler` options;
419
+ - pre-configured in `config[:log_sampling_enabled]`;
420
+ - `log_sampling_percent` - (optional) `[Integer]`
421
+ - the percent of cases that should be logged;
422
+ - take an effect when `log_sampling_enalbed` is true;
423
+ - works in tandem with `log_sampling_enabled` and `log_sampler` options;
424
+ - pre-configured in `config[:log_sampling_percent]`;
425
+ - `log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
426
+ - percent-based log sampler that decides should be RQL case logged or not;
427
+ - works in tandem with `log_sampling_enabled` and `log_sampling_percent` options;
428
+ - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
429
+ method so the algorithm error is ~(0%..13%);
430
+ - you can provide your own log sampler with bettter algorithm that should realize
431
+ `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
432
+ - pre-configured in `config[:log_sampler]`;
433
+ - `instr_sampling_enabled` - (optional) `[Boolean]`
434
+ - enables **instrumentaion sampling**: only the configured percent of RQL cases will be instrumented;
435
+ - disabled by default;
436
+ - works in tandem with `instr_sampling_percent` and `instr_sampler` options;
437
+ - pre-configured in `config[:instr_sampling_enabled]`;
438
+ - `instr_sampling_percent` - (optional) `[Integer]`
439
+ - the percent of cases that should be instrumented;
440
+ - take an effect when `instr_sampling_enalbed` is true;
441
+ - works in tandem with `instr_sampling_enabled` and `instr_sampler` options;
442
+ - pre-configured in `config[:instr_sampling_percent]`;
443
+ - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
444
+ - percent-based log sampler that decides should be RQL case instrumented or not;
445
+ - works in tandem with `instr_sampling_enabled` and `instr_sampling_percent` options;
446
+ - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
447
+ method so the algorithm error is ~(0%..13%);
448
+ - you can provide your own log sampler with bettter algorithm that should realize
449
+ `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
450
+ - pre-configured in `config[:instr_sampler]`;
366
451
  - `block` - (optional) `[Block]`
367
452
  - A block of code that should be executed after the successfully acquired lock.
368
453
  - If block is **passed** the obtained lock will be released after the block execution or it's ttl (what will happen first);
@@ -516,7 +601,7 @@ rql.lock("my_lock", queue_ttl: 5, timeout: 10_000, retry_count: nil)
516
601
 
517
602
  # lock queue: =>
518
603
  [
519
- "rql:acq:123/456/567/676/374dd74324",
604
+ "rql:acq:123/456/567/676/374dd74324",
520
605
  "rql:acq:123/456/567/677/374dd74322", # <- long living lock
521
606
  "rql:acq:123/456/567/679/374dd74321",
522
607
  "rql:acq:123/456/567/683/374dd74322", # <== we are here
@@ -571,7 +656,14 @@ def lock!(
571
656
  logger: config[:logger],
572
657
  log_lock_try: config[:log_lock_try],
573
658
  instrument: nil,
659
+ instrumenter: config[:instrumenter],
574
660
  conflict_strategy: config[:default_conflict_strategy],
661
+ log_sampling_enabled: config[:log_sampling_enabled],
662
+ log_sampling_percent: config[:log_sampling_percent],
663
+ log_sampler: config[:log_sampler],
664
+ instr_sampling_enabled: config[:instr_sampling_enabled],
665
+ instr_sampling_percent: config[:instr_sampling_percent],
666
+ instr_sampler: config[:instr_sampler],
575
667
  &block
576
668
  )
577
669
  ```
@@ -743,6 +835,24 @@ rql.queued?("your_lock_name") # => true/false
743
835
  - `:instrument` - (optional) `[NilClass,Any]`;
744
836
  - custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
745
837
  - `nil` by default (no additional data);
838
+ - `:log_sampling_enabled` - (optional) `[Boolean]`
839
+ - enables **log sampling**;
840
+ - pre-configured in `config[:log_sampling_enabled]`;
841
+ - `:log_sampling_percent` - (optional) `[Integer]`
842
+ - **log sampling**:the percent of cases that should be logged;
843
+ - pre-configured in `config[:log_sampling_percent]`;
844
+ - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
845
+ - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
846
+ - pre-configured in `config[:log_sampler]`;
847
+ - `:instr_sampling_enabled` - (optional) `[Boolean]`
848
+ - enables **instrumentaion sampling**;
849
+ - pre-configured in `config[:instr_sampling_enabled]`;
850
+ - `instr_sampling_percent` - (optional) `[Integer]`
851
+ - the percent of cases that should be instrumented;
852
+ - pre-configured in `config[:instr_sampling_percent]`;
853
+ - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
854
+ - percent-based log sampler that decides should be RQL case instrumented or not;
855
+ - pre-configured in `config[:instr_sampler]`;
746
856
  - if you try to unlock non-existent lock you will receive `ok: true` result with operation timings
747
857
  and `:nothing_to_release` result factor inside;
748
858
 
@@ -793,6 +903,24 @@ rql.unlock("your_lock_name")
793
903
  - pre-configured value in `config[:isntrumenter]`;
794
904
  - `:instrument` - (optional) `[NilClass,Any]`
795
905
  - custom instrumentation data wich will be passed to the instrumenter's payload with `:instrument` key;
906
+ - `:log_sampling_enabled` - (optional) `[Boolean]`
907
+ - enables **log sampling**;
908
+ - pre-configured in `config[:log_sampling_enabled]`;
909
+ - `:log_sampling_percent` - (optional) `[Integer]`
910
+ - **log sampling**:the percent of cases that should be logged;
911
+ - pre-configured in `config[:log_sampling_percent]`;
912
+ - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
913
+ - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
914
+ - pre-configured in `config[:log_sampler]`;
915
+ - `:instr_sampling_enabled` - (optional) `[Boolean]`
916
+ - enables **instrumentaion sampling**;
917
+ - pre-configured in `config[:instr_sampling_enabled]`;
918
+ - `instr_sampling_percent` - (optional) `[Integer]`
919
+ - the percent of cases that should be instrumented;
920
+ - pre-configured in `config[:instr_sampling_percent]`;
921
+ - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
922
+ - percent-based log sampler that decides should be RQL case instrumented or not;
923
+ - pre-configured in `config[:instr_sampler]`;
796
924
  - returns:
797
925
  - `[Hash<Symbol,Numeric>]` - Format: `{ ok: true, result: Hash<Symbol,Numeric> }`;
798
926
  - result data:
@@ -825,9 +953,33 @@ rql.clear_locks
825
953
  - the lock name which ttl should be extended;
826
954
  - `milliseconds` - (required) `[Integer]`
827
955
  - how many milliseconds should be added to the lock's TTL;
956
+ - `:instrumenter` - (optional) `[#notify]`
957
+ - custom instrumenter object;
958
+ - pre-configured in `config[:instrumetner]`;
959
+ - `:instrument` - (optional) `[NilClass,Any]`;
960
+ - custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
961
+ - `nil` by default (no additional data);
828
962
  - `:logger` - (optional) `[::Logger,#debug]`
829
963
  - custom logger object;
830
964
  - pre-configured in `config[:logger]`;
965
+ - `:log_sampling_enabled` - (optional) `[Boolean]`
966
+ - enables **log sampling**;
967
+ - pre-configured in `config[:log_sampling_enabled]`;
968
+ - `:log_sampling_percent` - (optional) `[Integer]`
969
+ - **log sampling**:the percent of cases that should be logged;
970
+ - pre-configured in `config[:log_sampling_percent]`;
971
+ - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
972
+ - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
973
+ - pre-configured in `config[:log_sampler]`;
974
+ - `:instr_sampling_enabled` - (optional) `[Boolean]`
975
+ - enables **instrumentaion sampling**;
976
+ - pre-configured in `config[:instr_sampling_enabled]`;
977
+ - `instr_sampling_percent` - (optional) `[Integer]`
978
+ - the percent of cases that should be instrumented;
979
+ - pre-configured in `config[:instr_sampling_percent]`;
980
+ - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
981
+ - percent-based log sampler that decides should be RQL case instrumented or not;
982
+ - pre-configured in `config[:instr_sampler]`;
831
983
  - returns `{ ok: true, result: :ttl_extended }` when ttl is extended;
832
984
  - returns `{ ok: false, result: :async_expire_or_no_lock }` when a lock not found or a lock is already expired during
833
985
  some steps of invocation (see **Important** section below);
@@ -1056,6 +1208,24 @@ Accepts:
1056
1208
  - `:instrument` - (optional) `[NilClass,Any]`
1057
1209
  - custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
1058
1210
  - `nil` by default (no additional data);
1211
+ - `:log_sampling_enabled` - (optional) `[Boolean]`
1212
+ - enables **log sampling**;
1213
+ - pre-configured in `config[:log_sampling_enabled]`;
1214
+ - `:log_sampling_percent` - (optional) `[Integer]`
1215
+ - **log sampling**:the percent of cases that should be logged;
1216
+ - pre-configured in `config[:log_sampling_percent]`;
1217
+ - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
1218
+ - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
1219
+ - pre-configured in `config[:log_sampler]`;
1220
+ - `:instr_sampling_enabled` - (optional) `[Boolean]`
1221
+ - enables **instrumentaion sampling**;
1222
+ - pre-configured in `config[:instr_sampling_enabled]`;
1223
+ - `instr_sampling_percent` - (optional) `[Integer]`
1224
+ - the percent of cases that should be instrumented;
1225
+ - pre-configured in `config[:instr_sampling_percent]`;
1226
+ - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
1227
+ - percent-based log sampler that decides should be RQL case instrumented or not;
1228
+ - pre-configured in `config[:instr_sampler]`;
1059
1229
 
1060
1230
  Returns: `{ ok: true, processed_queues: Set<String> }` returns the list of processed lock queues;
1061
1231
 
@@ -1087,7 +1257,7 @@ rql.clear_dead_requests(dead_ttl: 60 * 60 * 1000) # 1 hour in milliseconds
1087
1257
  - by default behavior (`:wait_for_lock`) your lock obtaining process will work in a classic way (limits, retries, etc);
1088
1258
  - `:work_through`, `:extendable_work_through` works with limits too (timeouts, delays, etc), but the decision of
1089
1259
  "is your lock are obtained or not" is made as you work with **reentrant locks** (your process continues to use the lock without/with
1090
- lock's TTL accordingly);
1260
+ lock's TTL extension accordingly);
1091
1261
  - for current implementation details check:
1092
1262
  - [Configuration](#configuration) documentation: see `config.default_conflict_strategy` config docs;
1093
1263
  - [#lock](#lock---obtain-a-lock) method documentation: see `conflict_strategy` attribute docs and the method result data;
@@ -1264,8 +1434,6 @@ Detalized event semantics and payload structure:
1264
1434
  - support for `Dragonfly` database backend (https://github.com/dragonflydb/dragonfly) (https://www.dragonflydb.io/);
1265
1435
  - **Minor**:
1266
1436
  - Semantic error objects for unexpected Redis errors;
1267
- - change all `::Process.clock_gettime(::Process::CLOCK_MONOTONIC)` milliseconds-related invocations to
1268
- `::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :millisecond)` in order to reduce time-related math operations count;
1269
1437
  - **Experimental feature**: (non-`timed` locks): per-ruby-block-holding-the-lock sidecar `Ractor` and `in progress queue` in RedisDB that will extend
1270
1438
  the acquired lock for long-running blocks of code (that invoked "under" the lock
1271
1439
  whose ttl may expire before the block execution completes). It makes sense for non-`timed` locks *only*;
@@ -28,11 +28,13 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
28
28
  # @param fail_fast [Boolean]
29
29
  # @param conflict_strategy [Symbol]
30
30
  # @param meta [NilClass,Hash<String|Symbol,Any>]
31
+ # @param log_sampled [Boolean]
32
+ # @param instr_sampled [Boolean]
31
33
  # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Symbol|Hash<Symbol,Any> }
32
34
  #
33
35
  # @api private
34
36
  # @since 1.0.0
35
- # @version 1.3.0
37
+ # @version 1.6.0
36
38
  # rubocop:disable Metrics/MethodLength
37
39
  def try_to_lock(
38
40
  redis,
@@ -46,14 +48,16 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
46
48
  queue_ttl,
47
49
  fail_fast,
48
50
  conflict_strategy,
49
- meta
51
+ meta,
52
+ log_sampled,
53
+ instr_sampled
50
54
  )
51
55
  # Step X: intermediate invocation results
52
56
  inter_result = nil
53
57
  timestamp = nil
54
58
  spc_processed_timestamp = nil
55
59
 
56
- if log_lock_try
60
+ if log_sampled && log_lock_try
57
61
  run_non_critical do
58
62
  logger.debug do
59
63
  "[redis_queued_locks.try_lock.start] " \
@@ -66,7 +70,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
66
70
 
67
71
  # Step X: start to work with lock acquiring
68
72
  result = redis.with do |rconn|
69
- if log_lock_try
73
+ if log_sampled && log_lock_try
70
74
  run_non_critical do
71
75
  logger.debug do
72
76
  "[redis_queued_locks.try_lock.rconn_fetched] " \
@@ -88,7 +92,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
88
92
 
89
93
  # SP-Conflict Step X1: calculate the current deadlock status
90
94
  if current_lock_obtainer != nil && acquier_id == current_lock_obtainer
91
- if log_lock_try
95
+ if log_sampled && log_lock_try
92
96
  run_non_critical do
93
97
  logger.debug do
94
98
  "[redis_queued_locks.try_lock.same_process_conflict_detected] " \
@@ -124,7 +128,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
124
128
  end
125
129
  # rubocop:enable Lint/DuplicateBranch
126
130
 
127
- if log_lock_try
131
+ if log_sampled && log_lock_try
128
132
  run_non_critical do
129
133
  logger.debug do
130
134
  "[redis_queued_locks.try_lock.same_process_conflict_analyzed] " \
@@ -172,7 +176,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
172
176
  )
173
177
  inter_result = :extendable_conflict_work_through
174
178
 
175
- if log_lock_try
179
+ if log_sampled && log_lock_try
176
180
  run_non_critical do
177
181
  logger.debug do
178
182
  "[redis_queued_locks.try_lock.reentrant_lock__extend_and_work_through] " \
@@ -205,7 +209,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
205
209
  'l_spc_ts', (spc_processed_timestamp = Time.now.to_f)
206
210
  )
207
211
 
208
- if log_lock_try
212
+ if log_sampled && log_lock_try
209
213
  run_non_critical do
210
214
  logger.debug do
211
215
  "[redis_queued_locks.try_lock.reentrant_lock__work_through] " \
@@ -222,7 +226,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
222
226
  inter_result = :conflict_dead_lock
223
227
  spc_processed_timestamp = Time.now.to_f
224
228
 
225
- if log_lock_try
229
+ if log_sampled && log_lock_try
226
230
  logger.debug do
227
231
  "[redis_queued_locks.try_lock.single_process_lock_conflict__dead_lock] " \
228
232
  "lock_key => '#{lock_key}' " \
@@ -242,7 +246,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
242
246
  # Step 1: add an acquier to the lock acquirement queue
243
247
  rconn.call('ZADD', lock_key_queue, 'NX', acquier_position, acquier_id)
244
248
 
245
- if log_lock_try
249
+ if log_sampled && log_lock_try
246
250
  run_non_critical do
247
251
  logger.debug do
248
252
  "[redis_queued_locks.try_lock.acq_added_to_queue] " \
@@ -261,7 +265,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
261
265
  RedisQueuedLocks::Resource.acquier_dead_score(queue_ttl)
262
266
  )
263
267
 
264
- if log_lock_try
268
+ if log_sampled && log_lock_try
265
269
  run_non_critical do
266
270
  logger.debug do
267
271
  "[redis_queued_locks.try_lock.remove_expired_acqs] " \
@@ -275,7 +279,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
275
279
  # Step 3: get the actual acquier waiting in the queue
276
280
  waiting_acquier = Array(rconn.call('ZRANGE', lock_key_queue, '0', '0')).first
277
281
 
278
- if log_lock_try
282
+ if log_sampled && log_lock_try
279
283
  run_non_critical do
280
284
  logger.debug do
281
285
  "[redis_queued_locks.try_lock.get_first_from_queue] " \
@@ -290,7 +294,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
290
294
  # Step PRE-4.x: check if the request time limit is reached
291
295
  # (when the current try self-removes itself from queue (queue ttl has come))
292
296
  if waiting_acquier == nil
293
- if log_lock_try
297
+ if log_sampled && log_lock_try
294
298
  run_non_critical do
295
299
  logger.debug do
296
300
  "[redis_queued_locks.try_lock.exit__queue_ttl_reached] " \
@@ -306,7 +310,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
306
310
  elsif waiting_acquier != acquier_id
307
311
  # Step ROLLBACK 1.1: our time hasn't come yet. retry!
308
312
 
309
- if log_lock_try
313
+ if log_sampled && log_lock_try
310
314
  run_non_critical do
311
315
  logger.debug do
312
316
  "[redis_queued_locks.try_lock.exit__no_first] " \
@@ -329,7 +333,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
329
333
  if locked_by_acquier
330
334
  # Step ROLLBACK 2: required lock is stil acquired. retry!
331
335
 
332
- if log_lock_try
336
+ if log_sampled && log_lock_try
333
337
  run_non_critical do
334
338
  logger.debug do
335
339
  "[redis_queued_locks.try_lock.exit__lock_still_obtained] " \
@@ -363,7 +367,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
363
367
  # Step 6.3: set the lock expiration time in order to prevent "infinite locks"
364
368
  transact.call('PEXPIRE', lock_key, ttl) # NOTE: in milliseconds
365
369
 
366
- if log_lock_try
370
+ if log_sampled && log_lock_try
367
371
  run_non_critical do
368
372
  logger.debug do
369
373
  "[redis_queued_locks.try_lock.obtain__free_to_acquire] " \
@@ -482,12 +486,23 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
482
486
  # @param lock_key_queue [String]
483
487
  # @param queue_ttl [Integer]
484
488
  # @param acquier_id [String]
489
+ # @param log_sampled [Boolean]
490
+ # @param instr_sampled [Boolean]
485
491
  # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
486
492
  #
487
493
  # @api private
488
494
  # @since 1.0.0
489
- # @version 1.3.0
490
- def dequeue_from_lock_queue(redis, logger, lock_key, lock_key_queue, queue_ttl, acquier_id)
495
+ # @version 1.6.0
496
+ def dequeue_from_lock_queue(
497
+ redis,
498
+ logger,
499
+ lock_key,
500
+ lock_key_queue,
501
+ queue_ttl,
502
+ acquier_id,
503
+ log_sampled,
504
+ instr_sampled
505
+ )
491
506
  result = redis.call('ZREM', lock_key_queue, acquier_id)
492
507
 
493
508
  run_non_critical do
@@ -497,7 +512,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
497
512
  "queue_ttl => '#{queue_ttl}' " \
498
513
  "acq_id => '#{acquier_id}'"
499
514
  end
500
- end
515
+ end if log_sampled
501
516
 
502
517
  RedisQueuedLocks::Data[ok: true, result: result]
503
518
  end
@@ -24,6 +24,8 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
24
24
  # @param ttl [Integer,NilClass] Lock's time to live (in ms). Nil means "without timeout".
25
25
  # @param queue_ttl [Integer] Lock request lifetime.
26
26
  # @param block [Block] Custom logic that should be invoked unter the obtained lock.
27
+ # @param log_sampled [Boolean] Should the logic be logged or not.
28
+ # @param instr_sampled [Boolean] Should the logic be instrumented or not.
27
29
  # @param should_expire [Boolean] Should the lock be expired after the block invocation.
28
30
  # @param should_decrease [Boolean]
29
31
  # - Should decrease the lock TTL after the lock invocation;
@@ -32,6 +34,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
32
34
  #
33
35
  # @api private
34
36
  # @since 1.3.0
37
+ # @version 1.6.0
35
38
  # rubocop:disable Metrics/MethodLength
36
39
  def yield_expire(
37
40
  redis,
@@ -42,6 +45,8 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
42
45
  ttl_shift,
43
46
  ttl,
44
47
  queue_ttl,
48
+ log_sampled,
49
+ instr_sampled,
45
50
  should_expire,
46
51
  should_decrease,
47
52
  &block
@@ -69,12 +74,14 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
69
74
  "queue_ttl => #{queue_ttl} " \
70
75
  "acq_id => '#{acquier_id}'"
71
76
  end
72
- end
77
+ end if log_sampled
78
+
73
79
  redis.call('EXPIRE', lock_key, '0')
74
80
  elsif should_decrease
75
81
  finish_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :millisecond)
76
82
  spent_time = (finish_time - initial_time)
77
83
  decreased_ttl = ttl - spent_time - RedisQueuedLocks::Resource::REDIS_TIMESHIFT_ERROR
84
+
78
85
  if decreased_ttl > 0
79
86
  run_non_critical do
80
87
  logger.debug do
@@ -84,7 +91,8 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
84
91
  "queue_ttl => #{queue_ttl} " \
85
92
  "acq_id => '#{acquier_id}' " \
86
93
  end
87
- end
94
+ end if log_sampled
95
+
88
96
  # NOTE:# NOTE: EVAL signature -> <lua script>, (number of keys), *(keys), *(arguments)
89
97
  redis.call('EVAL', DECREASE_LOCK_PTTL, 1, lock_key, decreased_ttl)
90
98
  # TODO: upload scripts to the redis