redis_queued_locks 0.0.16 → 0.0.18
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 +11 -0
- data/README.md +105 -3
- data/lib/redis_queued_locks/acquier/release.rb +6 -4
- data/lib/redis_queued_locks/acquier/try.rb +9 -6
- data/lib/redis_queued_locks/acquier.rb +87 -14
- data/lib/redis_queued_locks/client.rb +35 -4
- data/lib/redis_queued_locks/data.rb +5 -0
- data/lib/redis_queued_locks/resource.rb +6 -0
- data/lib/redis_queued_locks/version.rb +2 -2
- data/lib/redis_queued_locks.rb +1 -0
- metadata +3 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: '0993079d1a7cca97094c741d65c4ef1e8a5694184212b6597960e0b3c91d83cb'
         | 
| 4 | 
            +
              data.tar.gz: 22535e254fa22db6bfb0225f391e3d4606ad680bb401034fcbdfcd8e93a1fc5c
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 7db77251aefc59a83a9727d756774f5eb6b30a156fd058d69ec5170d252cc8fb875b2f213da2e15a4bdf9f5565565aa5ca699545ac0a83dcbc333fbed8c7aec1
         | 
| 7 | 
            +
              data.tar.gz: 659c47a6aaa421ade9c7ffaea000a7133c1ba72f5ab0a2e66bc56f5ad72f84f4d9525fc86024e5d52b8196a6dfc7b0a714100462915a91405c97c3b3d77d3e26
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,16 @@ | |
| 1 1 | 
             
            ## [Unreleased]
         | 
| 2 2 |  | 
| 3 | 
            +
            ## [0.0.18] - 2024-03-04
         | 
| 4 | 
            +
            ### Changed
         | 
| 5 | 
            +
            - Semantic results for methods returning `{ ok: true/false, result: Any }` hash objects.
         | 
| 6 | 
            +
              Now these objects are represented as `RedisQueuedLocks::Data` objects inherited from `Hash`;
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ## [0.0.17] - 2024-02-29
         | 
| 9 | 
            +
            ### Added
         | 
| 10 | 
            +
            - `RedisQueuedLocks::Client#locks` - list of obtained locks;
         | 
| 11 | 
            +
            - `RedisQueuedLocks::Client#queues` - list of existing lock request queus;
         | 
| 12 | 
            +
            - `RedisQueuedLocks::Client#keys` - get list of taken locks and queues;
         | 
| 13 | 
            +
             | 
| 3 14 | 
             
            ## [0.0.16] - 2024-02-29
         | 
| 4 15 | 
             
            ### Fixed
         | 
| 5 16 | 
             
            - Execution delay formula returns the value "in seconds" (should be "in milliseconds");
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # RedisQueuedLocks | 
| 1 | 
            +
            # RedisQueuedLocks
         | 
| 2 2 |  | 
| 3 3 | 
             
            Distributed locks with "lock acquisition queue" capabilities based on the Redis Database.
         | 
| 4 4 |  | 
| @@ -21,6 +21,10 @@ Each lock request is put into the request queue and processed in order of their | |
| 21 21 | 
             
              - [queued?](#queued)
         | 
| 22 22 | 
             
              - [unlock](#unlock---release-a-lock)
         | 
| 23 23 | 
             
              - [clear_locks](#clear_locks---release-all-locks-and-lock-queues)
         | 
| 24 | 
            +
              - [extend_lock_ttl](#extend_lock_ttl)
         | 
| 25 | 
            +
              - [locks](#locks---get-list-of-obtained-locks)
         | 
| 26 | 
            +
              - [queues](#queues---get-list-of-lock-request-queues)
         | 
| 27 | 
            +
              - [keys](#keys---get-list-of-taken-locks-and-queues)
         | 
| 24 28 | 
             
            - [Instrumentation](#instrumentation)
         | 
| 25 29 | 
             
              - [Instrumentation Events](#instrumentation-events)
         | 
| 26 30 | 
             
            - [Roadmap](#roadmap)
         | 
| @@ -104,10 +108,15 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config| | |
| 104 108 | 
             
              config.default_queue_ttl = 15
         | 
| 105 109 |  | 
| 106 110 | 
             
              # (default: 100)
         | 
| 107 | 
            -
              # - how many items will be released at a time in RedisQueuedLocks::Client#clear_locks logic;
         | 
| 108 | 
            -
              # - affects the performancs  | 
| 111 | 
            +
              # - how many items will be released at a time in RedisQueuedLocks::Client#clear_locks logic (uses SCAN);
         | 
| 112 | 
            +
              # - affects the performancs of your Redis and Ruby Application (configure thoughtfully);
         | 
| 109 113 | 
             
              config.lock_release_batch_size = 100
         | 
| 110 114 |  | 
| 115 | 
            +
              # (default: 500)
         | 
| 116 | 
            +
              # - how many items should be extracted from redis during the #locks, #queues and #keys operations (uses SCAN);
         | 
| 117 | 
            +
              # - affects the performance of your Redis and Ruby Application (configure thoughtfully;)
         | 
| 118 | 
            +
              config.key_extraction_batch_size = 500
         | 
| 119 | 
            +
             | 
| 111 120 | 
             
              # (default: RedisQueuedLocks::Instrument::VoidNotifier)
         | 
| 112 121 | 
             
              # - instrumentation layer;
         | 
| 113 122 | 
             
              # - you can provde your own instrumenter with `#notify(event, payload = {})`
         | 
| @@ -138,6 +147,10 @@ end | |
| 138 147 | 
             
            - [queued?](#queued)
         | 
| 139 148 | 
             
            - [unlock](#unlock---release-a-lock)
         | 
| 140 149 | 
             
            - [clear_locks](#clear_locks---release-all-locks-and-lock-queues)
         | 
| 150 | 
            +
            - [extend_lock_ttl](#extend_lock_ttl)
         | 
| 151 | 
            +
            - [locks](#locks---get-list-of-obtained-locks)
         | 
| 152 | 
            +
            - [queues](#queues---get-list-of-lock-request-queues)
         | 
| 153 | 
            +
            - [keys](#keys---get-list-of-taken-locks-and-queues)
         | 
| 141 154 |  | 
| 142 155 | 
             
            ---
         | 
| 143 156 |  | 
| @@ -231,6 +244,7 @@ Return value: | |
| 231 244 | 
             
            #### #lock! - exceptional lock obtaining
         | 
| 232 245 |  | 
| 233 246 | 
             
            - fails when (and with):
         | 
| 247 | 
            +
              - (`RedisQueuedLocks::LockAlreadyObtainedError`) when `fail_fast` is `true` and lock is already obtained;
         | 
| 234 248 | 
             
              - (`RedisQueuedLocks::LockAcquiermentTimeoutError`) `timeout` limit reached before lock is obtained;
         | 
| 235 249 | 
             
              - (`RedisQueuedLocks::LockAcquiermentRetryLimitError`) `retry_count` limit reached before lock is obtained;
         | 
| 236 250 |  | 
| @@ -393,6 +407,94 @@ Return: | |
| 393 407 |  | 
| 394 408 | 
             
            ---
         | 
| 395 409 |  | 
| 410 | 
            +
            #### #extend_lock_ttl
         | 
| 411 | 
            +
             | 
| 412 | 
            +
            - soon
         | 
| 413 | 
            +
             | 
| 414 | 
            +
            ---
         | 
| 415 | 
            +
             | 
| 416 | 
            +
            #### #locks - get list of obtained locks
         | 
| 417 | 
            +
             | 
| 418 | 
            +
            - uses redis `SCAN` under the hood;
         | 
| 419 | 
            +
            - accepts `scan_size:`/`Integer` option (`config[:key_extraction_batch_size]` by default);
         | 
| 420 | 
            +
            - returns `Set<String>`
         | 
| 421 | 
            +
             | 
| 422 | 
            +
            ```ruby
         | 
| 423 | 
            +
            rql.locks # or rql.locks(scan_size: 123)
         | 
| 424 | 
            +
             | 
| 425 | 
            +
            =>
         | 
| 426 | 
            +
            #<Set:
         | 
| 427 | 
            +
             {"rql:lock:locklock75",
         | 
| 428 | 
            +
              "rql:lock:locklock9",
         | 
| 429 | 
            +
              "rql:lock:locklock108",
         | 
| 430 | 
            +
              "rql:lock:locklock7",
         | 
| 431 | 
            +
              "rql:lock:locklock48",
         | 
| 432 | 
            +
              "rql:lock:locklock104",
         | 
| 433 | 
            +
              "rql:lock:locklock13",
         | 
| 434 | 
            +
              "rql:lock:locklock62",
         | 
| 435 | 
            +
              "rql:lock:locklock80",
         | 
| 436 | 
            +
              "rql:lock:locklock28",
         | 
| 437 | 
            +
              ...}>
         | 
| 438 | 
            +
            ```
         | 
| 439 | 
            +
             | 
| 440 | 
            +
            ---
         | 
| 441 | 
            +
             | 
| 442 | 
            +
            #### #queues - get list of lock request queues
         | 
| 443 | 
            +
             | 
| 444 | 
            +
            - uses redis `SCAN` under the hood;
         | 
| 445 | 
            +
            - accepts `scan_size:`/`Integer` option (`config[:key_extraction_batch_size]` by default);
         | 
| 446 | 
            +
            - returns `Set<String>`
         | 
| 447 | 
            +
             | 
| 448 | 
            +
            ```ruby
         | 
| 449 | 
            +
            rql.queues # or rql.queues(scan_size: 123)
         | 
| 450 | 
            +
             | 
| 451 | 
            +
            =>
         | 
| 452 | 
            +
            #<Set:
         | 
| 453 | 
            +
             {"rql:lock_queue:locklock75",
         | 
| 454 | 
            +
              "rql:lock_queue:locklock9",
         | 
| 455 | 
            +
              "rql:lock_queue:locklock108",
         | 
| 456 | 
            +
              "rql:lock_queue:locklock7",
         | 
| 457 | 
            +
              "rql:lock_queue:locklock48",
         | 
| 458 | 
            +
              "rql:lock_queue:locklock104",
         | 
| 459 | 
            +
              "rql:lock_queue:locklock13",
         | 
| 460 | 
            +
              "rql:lock_queue:locklock62",
         | 
| 461 | 
            +
              "rql:lock_queue:locklock80",
         | 
| 462 | 
            +
              "rql:lock_queue:locklock28",
         | 
| 463 | 
            +
              ...}>
         | 
| 464 | 
            +
            ```
         | 
| 465 | 
            +
             | 
| 466 | 
            +
            ---
         | 
| 467 | 
            +
             | 
| 468 | 
            +
            #### #keys - get list of taken locks and queues
         | 
| 469 | 
            +
             | 
| 470 | 
            +
            - uses redis `SCAN` under the hood;
         | 
| 471 | 
            +
            - accepts `scan_size:`/`Integer` option (`config[:key_extraction_batch_size]` by default);
         | 
| 472 | 
            +
            - returns `Set<String>`
         | 
| 473 | 
            +
             | 
| 474 | 
            +
            ```ruby
         | 
| 475 | 
            +
            rql.keys # or rql.keys(scan_size: 123)
         | 
| 476 | 
            +
             | 
| 477 | 
            +
            =>
         | 
| 478 | 
            +
            #<Set:
         | 
| 479 | 
            +
             {"rql:lock_queue:locklock75",
         | 
| 480 | 
            +
              "rql:lock_queue:locklock9",
         | 
| 481 | 
            +
              "rql:lock:locklock9",
         | 
| 482 | 
            +
              "rql:lock_queue:locklock108",
         | 
| 483 | 
            +
              "rql:lock_queue:locklock7",
         | 
| 484 | 
            +
              "rql:lock:locklock7",
         | 
| 485 | 
            +
              "rql:lock_queue:locklock48",
         | 
| 486 | 
            +
              "rql:lock_queue:locklock104",
         | 
| 487 | 
            +
              "rql:lock:locklock104",
         | 
| 488 | 
            +
              "rql:lock_queue:locklock13",
         | 
| 489 | 
            +
              "rql:lock_queue:locklock62",
         | 
| 490 | 
            +
              "rql:lock_queue:locklock80",
         | 
| 491 | 
            +
              "rql:lock:locklock80",
         | 
| 492 | 
            +
              "rql:lock_queue:locklock28",
         | 
| 493 | 
            +
              ...}>
         | 
| 494 | 
            +
            ```
         | 
| 495 | 
            +
             | 
| 496 | 
            +
            ---
         | 
| 497 | 
            +
             | 
| 396 498 | 
             
            ## Instrumentation
         | 
| 397 499 |  | 
| 398 500 | 
             
            An instrumentation layer is incapsulated in `instrumenter` object stored in [config](#configuration) (`RedisQueuedLocks::Client#config[:instrumenter]`).
         | 
| @@ -8,7 +8,7 @@ module RedisQueuedLocks::Acquier::Release | |
| 8 8 | 
             
              # @param redis [RedisClient]
         | 
| 9 9 | 
             
              # @param lock_key [String]
         | 
| 10 10 | 
             
              # @param lock_key_queue [String]
         | 
| 11 | 
            -
              # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
         | 
| 11 | 
            +
              # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
         | 
| 12 12 | 
             
              #
         | 
| 13 13 | 
             
              # @api private
         | 
| 14 14 | 
             
              # @since 0.1.0
         | 
| @@ -18,14 +18,14 @@ module RedisQueuedLocks::Acquier::Release | |
| 18 18 | 
             
                  transact.call('EXPIRE', lock_key, '0')
         | 
| 19 19 | 
             
                end
         | 
| 20 20 |  | 
| 21 | 
            -
                 | 
| 21 | 
            +
                RedisQueuedLocks::Data[ok: true, result:]
         | 
| 22 22 | 
             
              end
         | 
| 23 23 |  | 
| 24 24 | 
             
              # Release all locks: clear all lock queus and expire all locks.
         | 
| 25 25 | 
             
              #
         | 
| 26 26 | 
             
              # @param redis [RedisClient]
         | 
| 27 27 | 
             
              # @param batch_size [Integer]
         | 
| 28 | 
            -
              # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
         | 
| 28 | 
            +
              # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
         | 
| 29 29 | 
             
              #
         | 
| 30 30 | 
             
              # @api private
         | 
| 31 31 | 
             
              # @since 0.1.0
         | 
| @@ -37,6 +37,7 @@ module RedisQueuedLocks::Acquier::Release | |
| 37 37 | 
             
                    RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN,
         | 
| 38 38 | 
             
                    count: batch_size
         | 
| 39 39 | 
             
                  ) do |lock_queue|
         | 
| 40 | 
            +
                    # TODO: reduce unnecessary iterations
         | 
| 40 41 | 
             
                    pipeline.call('ZREMRANGEBYSCORE', lock_queue, '-inf', '+inf')
         | 
| 41 42 | 
             
                    pipeline.call('EXPIRE', RedisQueuedLocks::Resource.lock_key_from_queue(lock_queue), '0')
         | 
| 42 43 | 
             
                  end
         | 
| @@ -47,12 +48,13 @@ module RedisQueuedLocks::Acquier::Release | |
| 47 48 | 
             
                    RedisQueuedLocks::Resource::LOCK_PATTERN,
         | 
| 48 49 | 
             
                    count: batch_size
         | 
| 49 50 | 
             
                  ) do |lock_key|
         | 
| 51 | 
            +
                    # TODO: reduce unnecessary iterations
         | 
| 50 52 | 
             
                    pipeline.call('EXPIRE', lock_key, '0')
         | 
| 51 53 | 
             
                  end
         | 
| 52 54 | 
             
                end
         | 
| 53 55 |  | 
| 54 56 | 
             
                rel_keys = result.count { |red_res| red_res == 0 }
         | 
| 55 57 |  | 
| 56 | 
            -
                 | 
| 58 | 
            +
                RedisQueuedLocks::Data[ok: true, result: { rel_keys: rel_keys }]
         | 
| 57 59 | 
             
              end
         | 
| 58 60 | 
             
            end
         | 
| @@ -130,13 +130,13 @@ module RedisQueuedLocks::Acquier::Try | |
| 130 130 | 
             
                case
         | 
| 131 131 | 
             
                when fail_fast && inter_result == :fail_fast_no_try
         | 
| 132 132 | 
             
                  # Step 7.a: lock is still acquired and we should exit from the logic as soon as possible
         | 
| 133 | 
            -
                   | 
| 133 | 
            +
                  RedisQueuedLocks::Data[ok: false, result: inter_result]
         | 
| 134 134 | 
             
                when inter_result == :lock_is_still_acquired || inter_result == :acquier_is_not_first_in_queue
         | 
| 135 135 | 
             
                  # Step 7.b: lock is still acquired by another process => failed to acquire
         | 
| 136 | 
            -
                   | 
| 136 | 
            +
                  RedisQueuedLocks::Data[ok: false, result: inter_result]
         | 
| 137 137 | 
             
                when result == nil || (result.is_a?(::Array) && result.empty?)
         | 
| 138 138 | 
             
                  # Step 7.c: lock is already acquired durign the acquire race => failed to acquire
         | 
| 139 | 
            -
                   | 
| 139 | 
            +
                  RedisQueuedLocks::Data[ok: false, result: :lock_is_acquired_during_acquire_race]
         | 
| 140 140 | 
             
                when result.is_a?(::Array) && result.size == 3 # NOTE: 3 is a count of redis lock commands
         | 
| 141 141 | 
             
                  # TODO:
         | 
| 142 142 | 
             
                  #   => (!) analyze the command result and do actions with the depending on it;
         | 
| @@ -147,10 +147,13 @@ module RedisQueuedLocks::Acquier::Try | |
| 147 147 | 
             
                  #   3. pexpire should return 1 (expiration time is successfully applied)
         | 
| 148 148 |  | 
| 149 149 | 
             
                  # Step 7.d: locked! :) let's go! => successfully acquired
         | 
| 150 | 
            -
                   | 
| 150 | 
            +
                  RedisQueuedLocks::Data[
         | 
| 151 | 
            +
                    ok: true,
         | 
| 152 | 
            +
                    result: { lock_key: lock_key, acq_id: acquier_id, ts: timestamp, ttl: ttl }
         | 
| 153 | 
            +
                  ]
         | 
| 151 154 | 
             
                else
         | 
| 152 155 | 
             
                  # Ste 7.3: unknown behaviour :thinking:
         | 
| 153 | 
            -
                   | 
| 156 | 
            +
                  RedisQueuedLocks::Data[ok: false, result: :unknown]
         | 
| 154 157 | 
             
                end
         | 
| 155 158 | 
             
                # rubocop:enable Lint/DuplicateBranch
         | 
| 156 159 | 
             
              end
         | 
| @@ -170,6 +173,6 @@ module RedisQueuedLocks::Acquier::Try | |
| 170 173 | 
             
                  "Step ~ [СМЕРТЬ ПРОЦЕССА]: [#{acquier_id} :: #{lock_key_queue}] РЕЗУЛЬТАТ: #{result}"
         | 
| 171 174 | 
             
                )
         | 
| 172 175 |  | 
| 173 | 
            -
                 | 
| 176 | 
            +
                RedisQueuedLocks::Data[ok: true, result: result]
         | 
| 174 177 | 
             
              end
         | 
| 175 178 | 
             
            end
         | 
| @@ -63,7 +63,7 @@ module RedisQueuedLocks::Acquier | |
| 63 63 | 
             
                #   already obtained.
         | 
| 64 64 | 
             
                # @param [Block]
         | 
| 65 65 | 
             
                #   A block of code that should be executed after the successfully acquired lock.
         | 
| 66 | 
            -
                # @return [Hash<Symbol,Any>,yield]
         | 
| 66 | 
            +
                # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>,yield]
         | 
| 67 67 | 
             
                #  - Format: { ok: true/false, result: Any }
         | 
| 68 68 | 
             
                #  - If block is given the result of block's yeld will be returned.
         | 
| 69 69 | 
             
                #
         | 
| @@ -232,7 +232,7 @@ module RedisQueuedLocks::Acquier | |
| 232 232 | 
             
                        end
         | 
| 233 233 | 
             
                      end
         | 
| 234 234 | 
             
                    else
         | 
| 235 | 
            -
                       | 
| 235 | 
            +
                      RedisQueuedLocks::Data[ok: true, result: acq_process[:lock_info]]
         | 
| 236 236 | 
             
                    end
         | 
| 237 237 | 
             
                  else
         | 
| 238 238 | 
             
                    if acq_process[:result] != :retry_limit_reached &&
         | 
| @@ -245,7 +245,7 @@ module RedisQueuedLocks::Acquier | |
| 245 245 | 
             
                      acq_process[:result] = :timeout_reached
         | 
| 246 246 | 
             
                    end
         | 
| 247 247 | 
             
                    # Step 3.b: lock is not acquired (acquier is dequeued by timeout callback)
         | 
| 248 | 
            -
                     | 
| 248 | 
            +
                    RedisQueuedLocks::Data[ok: false, result: acq_process[:result]]
         | 
| 249 249 | 
             
                  end
         | 
| 250 250 | 
             
                end
         | 
| 251 251 | 
             
                # rubocop:enable Metrics/MethodLength, Metrics/BlockNesting
         | 
| @@ -257,10 +257,14 @@ module RedisQueuedLocks::Acquier | |
| 257 257 | 
             
                # It is safe because the lock obtain logic is transactional and
         | 
| 258 258 | 
             
                # watches the original lock for changes.
         | 
| 259 259 | 
             
                #
         | 
| 260 | 
            -
                # @param redis [RedisClient] | 
| 261 | 
            -
                #  | 
| 262 | 
            -
                # @param  | 
| 263 | 
            -
                #  | 
| 260 | 
            +
                # @param redis [RedisClient]
         | 
| 261 | 
            +
                #   Redis connection client.
         | 
| 262 | 
            +
                # @param lock_name [String]
         | 
| 263 | 
            +
                #   The lock name that should be released.
         | 
| 264 | 
            +
                # @param isntrumenter [#notify]
         | 
| 265 | 
            +
                #   See RedisQueuedLocks::Instrument::ActiveSupport for example.
         | 
| 266 | 
            +
                # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>]
         | 
| 267 | 
            +
                #   Format: { ok: true/false, result: Hash<Symbil,Numeric|String> }
         | 
| 264 268 | 
             
                #
         | 
| 265 269 | 
             
                # @api private
         | 
| 266 270 | 
             
                # @since 0.1.0
         | 
| @@ -283,17 +287,24 @@ module RedisQueuedLocks::Acquier | |
| 283 287 | 
             
                    })
         | 
| 284 288 | 
             
                  end
         | 
| 285 289 |  | 
| 286 | 
            -
                   | 
| 290 | 
            +
                  RedisQueuedLocks::Data[
         | 
| 291 | 
            +
                    ok: true,
         | 
| 292 | 
            +
                    result: { rel_time: rel_time, rel_key: lock_key, rel_queue: lock_key_queue }
         | 
| 293 | 
            +
                  ]
         | 
| 287 294 | 
             
                end
         | 
| 288 295 |  | 
| 289 296 | 
             
                # Release all locks:
         | 
| 290 297 | 
             
                # - 1. clear all lock queus: drop them all from Redis database by the lock queue pattern;
         | 
| 291 298 | 
             
                # - 2. delete all locks: drop lock keys from Redis by the lock key pattern;
         | 
| 292 299 | 
             
                #
         | 
| 293 | 
            -
                # @param redis [RedisClient] | 
| 294 | 
            -
                #  | 
| 295 | 
            -
                # @param  | 
| 296 | 
            -
                #  | 
| 300 | 
            +
                # @param redis [RedisClient]
         | 
| 301 | 
            +
                #   Redis connection client.
         | 
| 302 | 
            +
                # @param batch_size [Integer]
         | 
| 303 | 
            +
                #   The number of lock keys that should be released in a time.
         | 
| 304 | 
            +
                # @param isntrumenter [#notify]
         | 
| 305 | 
            +
                #   See RedisQueuedLocks::Instrument::ActiveSupport for example.
         | 
| 306 | 
            +
                # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>]
         | 
| 307 | 
            +
                #   Format: { ok: true/false, result: Hash<Symbol,Numeric> }
         | 
| 297 308 | 
             
                #
         | 
| 298 309 | 
             
                # @api private
         | 
| 299 310 | 
             
                # @since 0.1.0
         | 
| @@ -312,7 +323,10 @@ module RedisQueuedLocks::Acquier | |
| 312 323 | 
             
                    })
         | 
| 313 324 | 
             
                  end
         | 
| 314 325 |  | 
| 315 | 
            -
                   | 
| 326 | 
            +
                  RedisQueuedLocks::Data[
         | 
| 327 | 
            +
                    ok: true,
         | 
| 328 | 
            +
                    result: { rel_key_cnt: result[:rel_keys], rel_time: rel_time }
         | 
| 329 | 
            +
                  ]
         | 
| 316 330 | 
             
                end
         | 
| 317 331 |  | 
| 318 332 | 
             
                # @param redis_client [RedisClient]
         | 
| @@ -437,7 +451,66 @@ module RedisQueuedLocks::Acquier | |
| 437 451 | 
             
                #
         | 
| 438 452 | 
             
                # @api private
         | 
| 439 453 | 
             
                # @since 0.1.0
         | 
| 440 | 
            -
                def extend_lock_ttl(redis_client, lock_name, milliseconds) | 
| 454 | 
            +
                def extend_lock_ttl(redis_client, lock_name, milliseconds)
         | 
| 455 | 
            +
                  # TODO: realize
         | 
| 456 | 
            +
                end
         | 
| 457 | 
            +
             | 
| 458 | 
            +
                # @param redis_client [RedisClient]
         | 
| 459 | 
            +
                # @option scan_size [Integer]
         | 
| 460 | 
            +
                # @return [Set<String>]
         | 
| 461 | 
            +
                #
         | 
| 462 | 
            +
                # @api private
         | 
| 463 | 
            +
                # @since 0.1.0
         | 
| 464 | 
            +
                def locks(redis_client, scan_size:)
         | 
| 465 | 
            +
                  Set.new.tap do |lock_keys|
         | 
| 466 | 
            +
                    redis_client.scan(
         | 
| 467 | 
            +
                      'MATCH',
         | 
| 468 | 
            +
                      RedisQueuedLocks::Resource::LOCK_PATTERN,
         | 
| 469 | 
            +
                      count: scan_size
         | 
| 470 | 
            +
                    ) do |lock_key|
         | 
| 471 | 
            +
                      # TODO: reduce unnecessary iterations
         | 
| 472 | 
            +
                      lock_keys.add(lock_key)
         | 
| 473 | 
            +
                    end
         | 
| 474 | 
            +
                  end
         | 
| 475 | 
            +
                end
         | 
| 476 | 
            +
             | 
| 477 | 
            +
                # @param redis_client [RedisClient]
         | 
| 478 | 
            +
                # @param scan_size [Integer]
         | 
| 479 | 
            +
                # @return [Set<String>]
         | 
| 480 | 
            +
                #
         | 
| 481 | 
            +
                # @api private
         | 
| 482 | 
            +
                # @since 0.1.0
         | 
| 483 | 
            +
                def queues(redis_client, scan_size:)
         | 
| 484 | 
            +
                  Set.new.tap do |lock_queues|
         | 
| 485 | 
            +
                    redis_client.scan(
         | 
| 486 | 
            +
                      'MATCH',
         | 
| 487 | 
            +
                      RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN,
         | 
| 488 | 
            +
                      count: scan_size
         | 
| 489 | 
            +
                    ) do |lock_queue|
         | 
| 490 | 
            +
                      # TODO: reduce unnecessary iterations
         | 
| 491 | 
            +
                      lock_queues.add(lock_queue)
         | 
| 492 | 
            +
                    end
         | 
| 493 | 
            +
                  end
         | 
| 494 | 
            +
                end
         | 
| 495 | 
            +
             | 
| 496 | 
            +
                # @param redis_client [RedisClient]
         | 
| 497 | 
            +
                # @option scan_size [Integer]
         | 
| 498 | 
            +
                # @return [Array<String>]
         | 
| 499 | 
            +
                #
         | 
| 500 | 
            +
                # @api private
         | 
| 501 | 
            +
                # @since 0.1.0
         | 
| 502 | 
            +
                def keys(redis_client, scan_size:)
         | 
| 503 | 
            +
                  Set.new.tap do |keys|
         | 
| 504 | 
            +
                    redis_client.scan(
         | 
| 505 | 
            +
                      'MATCH',
         | 
| 506 | 
            +
                      RedisQueuedLocks::Resource::KEY_PATTERN,
         | 
| 507 | 
            +
                      count: scan_size
         | 
| 508 | 
            +
                    ) do |key|
         | 
| 509 | 
            +
                      # TODO: reduce unnecessary iterations
         | 
| 510 | 
            +
                      keys.add(key)
         | 
| 511 | 
            +
                    end
         | 
| 512 | 
            +
                  end
         | 
| 513 | 
            +
                end
         | 
| 441 514 |  | 
| 442 515 | 
             
                private
         | 
| 443 516 |  | 
| @@ -15,6 +15,7 @@ class RedisQueuedLocks::Client | |
| 15 15 | 
             
                setting :default_lock_ttl, 5_000 # NOTE: milliseconds
         | 
| 16 16 | 
             
                setting :default_queue_ttl, 15 # NOTE: seconds
         | 
| 17 17 | 
             
                setting :lock_release_batch_size, 100
         | 
| 18 | 
            +
                setting :key_extraction_batch_size, 500
         | 
| 18 19 | 
             
                setting :instrumenter, RedisQueuedLocks::Instrument::VoidNotifier
         | 
| 19 20 | 
             
                setting :uniq_identifier, -> { RedisQueuedLocks::Resource.calc_uniq_identity }
         | 
| 20 21 |  | 
| @@ -91,7 +92,7 @@ class RedisQueuedLocks::Client | |
| 91 92 | 
             
              #   by another process while the lock request queue was initially empty;
         | 
| 92 93 | 
             
              # @param block [Block]
         | 
| 93 94 | 
             
              #   A block of code that should be executed after the successfully acquired lock.
         | 
| 94 | 
            -
              # @return [Hash<Symbol,Any>,yield]
         | 
| 95 | 
            +
              # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>,yield]
         | 
| 95 96 | 
             
              #   - Format: { ok: true/false, result: Symbol/Hash }.
         | 
| 96 97 | 
             
              #   - If block is given the result of block's yeld will be returned.
         | 
| 97 98 | 
             
              #
         | 
| @@ -162,8 +163,10 @@ class RedisQueuedLocks::Client | |
| 162 163 | 
             
                )
         | 
| 163 164 | 
             
              end
         | 
| 164 165 |  | 
| 165 | 
            -
              # @param lock_name [String] | 
| 166 | 
            -
              #  | 
| 166 | 
            +
              # @param lock_name [String]
         | 
| 167 | 
            +
              #   The lock name that should be released.
         | 
| 168 | 
            +
              # @return [RedisQueuedLocks::Data, Hash<Symbol,Any>]
         | 
| 169 | 
            +
              #   Format: { ok: true/false, result: Symbol/Hash }.
         | 
| 167 170 | 
             
              #
         | 
| 168 171 | 
             
              # @api public
         | 
| 169 172 | 
             
              # @since 0.1.0
         | 
| @@ -218,12 +221,40 @@ class RedisQueuedLocks::Client | |
| 218 221 | 
             
              end
         | 
| 219 222 |  | 
| 220 223 | 
             
              # @option batch_size [Integer]
         | 
| 221 | 
            -
              # @return [Hash<Symbol,Any>] | 
| 224 | 
            +
              # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>]
         | 
| 225 | 
            +
              #   Format: { ok: true/false, result: Symbol/Hash }.
         | 
| 222 226 | 
             
              #
         | 
| 223 227 | 
             
              # @api public
         | 
| 224 228 | 
             
              # @since 0.1.0
         | 
| 225 229 | 
             
              def clear_locks(batch_size: config[:lock_release_batch_size])
         | 
| 226 230 | 
             
                RedisQueuedLocks::Acquier.release_all_locks!(redis_client, batch_size, config[:instrumenter])
         | 
| 227 231 | 
             
              end
         | 
| 232 | 
            +
             | 
| 233 | 
            +
              # @option scan_size [Integer]
         | 
| 234 | 
            +
              # @return [Set<String>]
         | 
| 235 | 
            +
              #
         | 
| 236 | 
            +
              # @api public
         | 
| 237 | 
            +
              # @since 0.1.0
         | 
| 238 | 
            +
              def locks(scan_size: config[:key_extraction_batch_size])
         | 
| 239 | 
            +
                RedisQueuedLocks::Acquier.locks(redis_client, scan_size:)
         | 
| 240 | 
            +
              end
         | 
| 241 | 
            +
             | 
| 242 | 
            +
              # @option scan_size [Integer]
         | 
| 243 | 
            +
              # @return [Set<String>]
         | 
| 244 | 
            +
              #
         | 
| 245 | 
            +
              # @api public
         | 
| 246 | 
            +
              # @since 0.1.0
         | 
| 247 | 
            +
              def queues(scan_size: config[:key_extraction_batch_size])
         | 
| 248 | 
            +
                RedisQueuedLocks::Acquier.queues(redis_client, scan_size:)
         | 
| 249 | 
            +
              end
         | 
| 250 | 
            +
             | 
| 251 | 
            +
              # @option scan_size [Integer]
         | 
| 252 | 
            +
              # @return [Set<String>]
         | 
| 253 | 
            +
              #
         | 
| 254 | 
            +
              # @api public
         | 
| 255 | 
            +
              # @since 0.1.0
         | 
| 256 | 
            +
              def keys(scan_size: config[:key_extraction_batch_size])
         | 
| 257 | 
            +
                RedisQueuedLocks::Acquier.keys(redis_client, scan_size:)
         | 
| 258 | 
            +
              end
         | 
| 228 259 | 
             
            end
         | 
| 229 260 | 
             
            # rubocop:enable Metrics/ClassLength
         | 
    
        data/lib/redis_queued_locks.rb
    CHANGED
    
    | @@ -10,6 +10,7 @@ require 'securerandom' | |
| 10 10 | 
             
            module RedisQueuedLocks
         | 
| 11 11 | 
             
              require_relative 'redis_queued_locks/version'
         | 
| 12 12 | 
             
              require_relative 'redis_queued_locks/errors'
         | 
| 13 | 
            +
              require_relative 'redis_queued_locks/data'
         | 
| 13 14 | 
             
              require_relative 'redis_queued_locks/debugger'
         | 
| 14 15 | 
             
              require_relative 'redis_queued_locks/resource'
         | 
| 15 16 | 
             
              require_relative 'redis_queued_locks/acquier'
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: redis_queued_locks
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.18
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Rustam Ibragimov
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024- | 
| 11 | 
            +
            date: 2024-03-04 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: redis-client
         | 
| @@ -61,6 +61,7 @@ files: | |
| 61 61 | 
             
            - lib/redis_queued_locks/acquier/release.rb
         | 
| 62 62 | 
             
            - lib/redis_queued_locks/acquier/try.rb
         | 
| 63 63 | 
             
            - lib/redis_queued_locks/client.rb
         | 
| 64 | 
            +
            - lib/redis_queued_locks/data.rb
         | 
| 64 65 | 
             
            - lib/redis_queued_locks/debugger.rb
         | 
| 65 66 | 
             
            - lib/redis_queued_locks/debugger/interface.rb
         | 
| 66 67 | 
             
            - lib/redis_queued_locks/errors.rb
         |