redis_queued_locks 1.12.1 → 1.14.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 +4 -4
 - data/.rubocop.yml +3 -1
 - data/.ruby-version +1 -1
 - data/CHANGELOG.md +45 -5
 - data/LICENSE.txt +1 -1
 - data/README.md +574 -296
 - data/Rakefile +12 -4
 - data/Steepfile +15 -0
 - data/github_ci/ruby3.3.gemfile +17 -0
 - data/github_ci/ruby3.3.gemfile.lock +217 -0
 - data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/delay_execution.rb +4 -4
 - data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +40 -0
 - data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/dequeue_from_lock_queue.rb +17 -8
 - data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +166 -0
 - data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +218 -0
 - data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +543 -0
 - data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/try_to_lock.rb +126 -92
 - data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/with_acq_timeout.rb +14 -9
 - data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +76 -0
 - data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/yield_expire.rb +42 -19
 - data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock.rb +74 -47
 - data/lib/redis_queued_locks/{acquier → acquirer}/clear_dead_requests.rb +5 -3
 - data/lib/redis_queued_locks/{acquier → acquirer}/extend_lock_ttl.rb +4 -3
 - data/lib/redis_queued_locks/{acquier → acquirer}/is_locked.rb +1 -1
 - data/lib/redis_queued_locks/{acquier → acquirer}/is_queued.rb +1 -1
 - data/lib/redis_queued_locks/{acquier → acquirer}/keys.rb +5 -5
 - data/lib/redis_queued_locks/{acquier → acquirer}/lock_info.rb +9 -5
 - data/lib/redis_queued_locks/{acquier → acquirer}/locks.rb +16 -3
 - data/lib/redis_queued_locks/{acquier → acquirer}/queue_info.rb +8 -6
 - data/lib/redis_queued_locks/{acquier → acquirer}/queues.rb +9 -2
 - data/lib/redis_queued_locks/{acquier → acquirer}/release_all_locks.rb +26 -21
 - data/lib/redis_queued_locks/{acquier → acquirer}/release_lock.rb +28 -22
 - data/lib/redis_queued_locks/acquirer/release_locks_of.rb +211 -0
 - data/lib/redis_queued_locks/acquirer.rb +19 -0
 - data/lib/redis_queued_locks/client.rb +317 -254
 - data/lib/redis_queued_locks/config/dsl.rb +94 -0
 - data/lib/redis_queued_locks/config.rb +236 -0
 - data/lib/redis_queued_locks/data.rb +2 -0
 - data/lib/redis_queued_locks/errors.rb +27 -11
 - data/lib/redis_queued_locks/instrument.rb +11 -4
 - data/lib/redis_queued_locks/logging/void_logger.rb +38 -1
 - data/lib/redis_queued_locks/logging.rb +20 -5
 - data/lib/redis_queued_locks/resource.rb +49 -11
 - data/lib/redis_queued_locks/swarm/acquirers.rb +17 -16
 - data/lib/redis_queued_locks/swarm/flush_zombies.rb +26 -25
 - data/lib/redis_queued_locks/swarm/probe_hosts.rb +20 -19
 - data/lib/redis_queued_locks/swarm/redis_client_builder.rb +3 -3
 - data/lib/redis_queued_locks/swarm/supervisor.rb +19 -6
 - data/lib/redis_queued_locks/swarm/swarm_element/isolated.rb +20 -18
 - data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +35 -27
 - data/lib/redis_queued_locks/swarm/zombie_info.rb +9 -9
 - data/lib/redis_queued_locks/swarm.rb +20 -41
 - data/lib/redis_queued_locks/utilities.rb +11 -2
 - data/lib/redis_queued_locks/version.rb +2 -2
 - data/lib/redis_queued_locks.rb +2 -3
 - data/rbs_collection.lock.yaml +28 -0
 - data/rbs_collection.yaml +17 -0
 - data/redis_queued_locks.gemspec +22 -23
 - data/sig/manifest.yml +6 -0
 - data/sig/redis_queued_locks/acquier.rbs +4 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/delay_execution.rbs +9 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +21 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +26 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +71 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +72 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +179 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +48 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rbs +19 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +41 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock/yield_with_expire/log_visitor.rbs +32 -0
 - data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +52 -0
 - data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +28 -0
 - data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +28 -0
 - data/sig/redis_queued_locks/acquirer/is_locked.rbs +9 -0
 - data/sig/redis_queued_locks/acquirer/is_queued.rbs +9 -0
 - data/sig/redis_queued_locks/acquirer/keys.rbs +10 -0
 - data/sig/redis_queued_locks/acquirer/lock_info.rbs +10 -0
 - data/sig/redis_queued_locks/acquirer/locks.rbs +16 -0
 - data/sig/redis_queued_locks/acquirer/queue_info.rbs +13 -0
 - data/sig/redis_queued_locks/acquirer/queues.rbs +16 -0
 - data/sig/redis_queued_locks/acquirer/release_all_locks.rbs +30 -0
 - data/sig/redis_queued_locks/acquirer/release_lock.rbs +38 -0
 - data/sig/redis_queued_locks/acquirer/release_locks_of.rbs +46 -0
 - data/sig/redis_queued_locks/client.rbs +235 -0
 - data/sig/redis_queued_locks/config/dsl.rbs +26 -0
 - data/sig/redis_queued_locks/config.rbs +23 -0
 - data/sig/redis_queued_locks/data.rbs +4 -0
 - data/sig/redis_queued_locks/debugger/interface.rbs +9 -0
 - data/sig/redis_queued_locks/debugger.rbs +13 -0
 - data/sig/redis_queued_locks/errors.rbs +43 -0
 - data/sig/redis_queued_locks/instrument/active_support.rbs +7 -0
 - data/sig/redis_queued_locks/instrument/sampler.rbs +9 -0
 - data/sig/redis_queued_locks/instrument/void_notifier.rbs +7 -0
 - data/sig/redis_queued_locks/instrument.rbs +15 -0
 - data/sig/redis_queued_locks/logging/sampler.rbs +9 -0
 - data/sig/redis_queued_locks/logging/void_logger.rbs +15 -0
 - data/sig/redis_queued_locks/logging.rbs +15 -0
 - data/sig/redis_queued_locks/resource.rbs +42 -0
 - data/sig/redis_queued_locks/swarm/acquirers.rbs +10 -0
 - data/sig/redis_queued_locks/swarm/flush_zombies.rbs +13 -0
 - data/sig/redis_queued_locks/swarm/probe_hosts.rbs +13 -0
 - data/sig/redis_queued_locks/swarm/redis_client_builder.rbs +19 -0
 - data/sig/redis_queued_locks/swarm/supervisor.rbs +26 -0
 - data/sig/redis_queued_locks/swarm/swarm_element/isolated.rbs +52 -0
 - data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +61 -0
 - data/sig/redis_queued_locks/swarm/swarm_element.rbs +8 -0
 - data/sig/redis_queued_locks/swarm/zombie_info.rbs +24 -0
 - data/sig/redis_queued_locks/swarm.rbs +41 -0
 - data/sig/redis_queued_locks/utilities/lock.rbs +10 -0
 - data/sig/redis_queued_locks/utilities.rbs +12 -0
 - data/sig/redis_queued_locks/version.rbs +3 -0
 - data/sig/redis_queued_locks.rbs +14 -0
 - data/sig/vendor/active_support.rbs +9 -0
 - data/sig/vendor/redis_client.rbs +39 -0
 - data/sig/vendor/semantic_logger.rbs +4 -0
 - metadata +98 -54
 - data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +0 -40
 - data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +0 -166
 - data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +0 -216
 - data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +0 -541
 - data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +0 -76
 - data/lib/redis_queued_locks/acquier.rb +0 -18
 
| 
         @@ -21,6 +21,18 @@ module RedisQueuedLocks::Resource 
     | 
|
| 
       21 
21 
     | 
    
         
             
              # @since 1.0.0
         
     | 
| 
       22 
22 
     | 
    
         
             
              LOCK_QUEUE_PATTERN = 'rql:lock_queue:*'
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
      
 24 
     | 
    
         
            +
              # @return [String]
         
     | 
| 
      
 25 
     | 
    
         
            +
              #
         
     | 
| 
      
 26 
     | 
    
         
            +
              # @api private
         
     | 
| 
      
 27 
     | 
    
         
            +
              # @since ?.?.?
         
     | 
| 
      
 28 
     | 
    
         
            +
              READ_LOCK_QUEUE_PATTERN = 'rql:lock_queue:*:read'
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              # @return [String]
         
     | 
| 
      
 31 
     | 
    
         
            +
              #
         
     | 
| 
      
 32 
     | 
    
         
            +
              # @api private
         
     | 
| 
      
 33 
     | 
    
         
            +
              # @since ?.?.?
         
     | 
| 
      
 34 
     | 
    
         
            +
              WRITE_LOCK_QUEUE_PATTERN = 'rql:lock_queue:*:write'
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
       24 
36 
     | 
    
         
             
              # @return [String]
         
     | 
| 
       25 
37 
     | 
    
         
             
              #
         
     | 
| 
       26 
38 
     | 
    
         
             
              # @api private
         
     | 
| 
         @@ -55,7 +67,7 @@ module RedisQueuedLocks::Resource 
     | 
|
| 
       55 
67 
     | 
    
         
             
                #
         
     | 
| 
       56 
68 
     | 
    
         
             
                # @api private
         
     | 
| 
       57 
69 
     | 
    
         
             
                # @since 1.0.0
         
     | 
| 
       58 
     | 
    
         
            -
                def  
     | 
| 
      
 70 
     | 
    
         
            +
                def acquirer_identifier(process_id, thread_id, fiber_id, ractor_id, identity)
         
     | 
| 
       59 
71 
     | 
    
         
             
                  "rql:acq:#{process_id}/#{thread_id}/#{fiber_id}/#{ractor_id}/#{identity}"
         
     | 
| 
       60 
72 
     | 
    
         
             
                end
         
     | 
| 
       61 
73 
     | 
    
         | 
| 
         @@ -93,20 +105,38 @@ module RedisQueuedLocks::Resource 
     | 
|
| 
       93 
105 
     | 
    
         
             
                  "rql:lock_queue:#{lock_name}"
         
     | 
| 
       94 
106 
     | 
    
         
             
                end
         
     | 
| 
       95 
107 
     | 
    
         | 
| 
      
 108 
     | 
    
         
            +
                # @param lock_name [String]
         
     | 
| 
      
 109 
     | 
    
         
            +
                # @return [String]
         
     | 
| 
      
 110 
     | 
    
         
            +
                #
         
     | 
| 
      
 111 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 112 
     | 
    
         
            +
                # @api ?.?.?
         
     | 
| 
      
 113 
     | 
    
         
            +
                def prepare_read_lock_queue(lock_name)
         
     | 
| 
      
 114 
     | 
    
         
            +
                  "rql:lock_queue:#{lock_name}:read"
         
     | 
| 
      
 115 
     | 
    
         
            +
                end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                # @param lock_name [String]
         
     | 
| 
      
 118 
     | 
    
         
            +
                # @return [String]
         
     | 
| 
      
 119 
     | 
    
         
            +
                #
         
     | 
| 
      
 120 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 121 
     | 
    
         
            +
                # @api ?.?.?
         
     | 
| 
      
 122 
     | 
    
         
            +
                def prepare_write_lock_queue(lock_name)
         
     | 
| 
      
 123 
     | 
    
         
            +
                  "rql:lock_queue:#{lock_name}:write"
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
       96 
126 
     | 
    
         
             
                # @return [Float] Redis's <Set> score that is calculated from the time (epoch) as a float.
         
     | 
| 
       97 
127 
     | 
    
         
             
                #
         
     | 
| 
       98 
128 
     | 
    
         
             
                # @api private
         
     | 
| 
       99 
129 
     | 
    
         
             
                # @since 1.0.0
         
     | 
| 
       100 
     | 
    
         
            -
                def  
     | 
| 
      
 130 
     | 
    
         
            +
                def calc_initial_acquirer_position
         
     | 
| 
       101 
131 
     | 
    
         
             
                  Time.now.to_f
         
     | 
| 
       102 
132 
     | 
    
         
             
                end
         
     | 
| 
       103 
133 
     | 
    
         | 
| 
       104 
     | 
    
         
            -
                # @param queue_ttl [ 
     | 
| 
       105 
     | 
    
         
            -
                # @return [Float] Redis's <Set> score barrier for  
     | 
| 
      
 134 
     | 
    
         
            +
                # @param queue_ttl [Numeric] In seconds
         
     | 
| 
      
 135 
     | 
    
         
            +
                # @return [Float] Redis's <Set> score barrier for acquirers that should be removed from queue.
         
     | 
| 
       106 
136 
     | 
    
         
             
                #
         
     | 
| 
       107 
137 
     | 
    
         
             
                # @api private
         
     | 
| 
       108 
138 
     | 
    
         
             
                # @since 1.0.0
         
     | 
| 
       109 
     | 
    
         
            -
                def  
     | 
| 
      
 139 
     | 
    
         
            +
                def acquirer_dead_score(queue_ttl)
         
     | 
| 
       110 
140 
     | 
    
         
             
                  Time.now.to_f - queue_ttl
         
     | 
| 
       111 
141 
     | 
    
         
             
                end
         
     | 
| 
       112 
142 
     | 
    
         | 
| 
         @@ -119,9 +149,9 @@ module RedisQueuedLocks::Resource 
     | 
|
| 
       119 
149 
     | 
    
         
             
                  Time.now.to_f - zombie_ttl
         
     | 
| 
       120 
150 
     | 
    
         
             
                end
         
     | 
| 
       121 
151 
     | 
    
         | 
| 
       122 
     | 
    
         
            -
                # @param  
     | 
| 
      
 152 
     | 
    
         
            +
                # @param acquirer_position [Float]
         
     | 
| 
       123 
153 
     | 
    
         
             
                #   A time (epoch, seconds.milliseconds) that represents
         
     | 
| 
       124 
     | 
    
         
            -
                #   the  
     | 
| 
      
 154 
     | 
    
         
            +
                #   the acquirer position in lock request queue.
         
     | 
| 
       125 
155 
     | 
    
         
             
                # @parma queue_ttl [Integer]
         
     | 
| 
       126 
156 
     | 
    
         
             
                #   In second.
         
     | 
| 
       127 
157 
     | 
    
         
             
                # @return [Boolean]
         
     | 
| 
         @@ -129,8 +159,8 @@ module RedisQueuedLocks::Resource 
     | 
|
| 
       129 
159 
     | 
    
         
             
                #
         
     | 
| 
       130 
160 
     | 
    
         
             
                # @api private
         
     | 
| 
       131 
161 
     | 
    
         
             
                # @since 1.0.0
         
     | 
| 
       132 
     | 
    
         
            -
                def dead_score_reached?( 
     | 
| 
       133 
     | 
    
         
            -
                  ( 
     | 
| 
      
 162 
     | 
    
         
            +
                def dead_score_reached?(acquirer_position, queue_ttl)
         
     | 
| 
      
 163 
     | 
    
         
            +
                  (acquirer_position + queue_ttl) < Time.now.to_f
         
     | 
| 
       134 
164 
     | 
    
         
             
                end
         
     | 
| 
       135 
165 
     | 
    
         | 
| 
       136 
166 
     | 
    
         
             
                # @param lock_queue [String]
         
     | 
| 
         @@ -186,13 +216,20 @@ module RedisQueuedLocks::Resource 
     | 
|
| 
       186 
216 
     | 
    
         
             
                  # NOTE №2: we have no any approach to count Fiber objects in the current process without
         
     | 
| 
       187 
217 
     | 
    
         
             
                  #   object space API (or super memory-expensive) so host identification works without fibers;
         
     | 
| 
       188 
218 
     | 
    
         
             
                  # NOTE №3: we still can extract thread objects via Thread.list API;
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
                  # @type var current_process_id: Integer
         
     | 
| 
       189 
221 
     | 
    
         
             
                  current_process_id = get_process_id
         
     | 
| 
      
 222 
     | 
    
         
            +
                  # @type var current_threads: Array[Thread]
         
     | 
| 
       190 
223 
     | 
    
         
             
                  current_threads = ::Thread.list
         
     | 
| 
      
 224 
     | 
    
         
            +
                  # @type var current_ractor_id: Integer
         
     | 
| 
       191 
225 
     | 
    
         
             
                  current_ractor_id = get_ractor_id
         
     | 
| 
       192 
226 
     | 
    
         | 
| 
       193 
     | 
    
         
            -
                  [] 
     | 
| 
      
 227 
     | 
    
         
            +
                  # NOTE: steep can't resolve a type of dynamic `[]` literal mutated via inline tap;
         
     | 
| 
      
 228 
     | 
    
         
            +
                  # steep:ignore:start
         
     | 
| 
      
 229 
     | 
    
         
            +
                  [].tap do |acquirers|
         
     | 
| 
      
 230 
     | 
    
         
            +
                    # @type var acquirers: Array[String]
         
     | 
| 
       194 
231 
     | 
    
         
             
                    current_threads.each do |thread|
         
     | 
| 
       195 
     | 
    
         
            -
                       
     | 
| 
      
 232 
     | 
    
         
            +
                      acquirers << host_identifier(
         
     | 
| 
       196 
233 
     | 
    
         
             
                        current_process_id,
         
     | 
| 
       197 
234 
     | 
    
         
             
                        thread.object_id,
         
     | 
| 
       198 
235 
     | 
    
         
             
                        current_ractor_id,
         
     | 
| 
         @@ -200,6 +237,7 @@ module RedisQueuedLocks::Resource 
     | 
|
| 
       200 
237 
     | 
    
         
             
                      )
         
     | 
| 
       201 
238 
     | 
    
         
             
                    end
         
     | 
| 
       202 
239 
     | 
    
         
             
                  end
         
     | 
| 
      
 240 
     | 
    
         
            +
                  # steep:ignore:end
         
     | 
| 
       203 
241 
     | 
    
         
             
                end
         
     | 
| 
       204 
242 
     | 
    
         
             
              end
         
     | 
| 
       205 
243 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,35 +5,36 @@ 
     | 
|
| 
       5 
5 
     | 
    
         
             
            module RedisQueuedLocks::Swarm::Acquirers
         
     | 
| 
       6 
6 
     | 
    
         
             
              class << self
         
     | 
| 
       7 
7 
     | 
    
         
             
                # Returns the list of swarm acquirers stored as HASH.
         
     | 
| 
       8 
     | 
    
         
            -
                # Format:
         
     | 
| 
       9 
     | 
    
         
            -
                #   {
         
     | 
| 
       10 
     | 
    
         
            -
                #     <acquirer id #1> => {
         
     | 
| 
       11 
     | 
    
         
            -
                #       zombie: <Boolean>,
         
     | 
| 
       12 
     | 
    
         
            -
                #       last_probe_time: <Time>,
         
     | 
| 
       13 
     | 
    
         
            -
                #       last_probe_score: <Numeric>
         
     | 
| 
       14 
     | 
    
         
            -
                #      },
         
     | 
| 
       15 
     | 
    
         
            -
                #     <acquirer id #2> => {
         
     | 
| 
       16 
     | 
    
         
            -
                #       zombie: <Boolean>,
         
     | 
| 
       17 
     | 
    
         
            -
                #       last_probe_time: <Time>,
         
     | 
| 
       18 
     | 
    
         
            -
                #       last_probe_score: <Numeric>
         
     | 
| 
       19 
     | 
    
         
            -
                #      },
         
     | 
| 
       20 
     | 
    
         
            -
                #     ...
         
     | 
| 
       21 
     | 
    
         
            -
                #   }
         
     | 
| 
       22 
8 
     | 
    
         
             
                # Liveness probe time is represented as a float value (Time.now.to_f initially).
         
     | 
| 
       23 
9 
     | 
    
         
             
                #
         
     | 
| 
       24 
10 
     | 
    
         
             
                # @param redis_client [RedisClient]
         
     | 
| 
       25 
11 
     | 
    
         
             
                # @param zombie_ttl [Integer]
         
     | 
| 
       26 
     | 
    
         
            -
                # @return [Hash<String,Hash<Symbol,Float|Time>>]
         
     | 
| 
      
 12 
     | 
    
         
            +
                # @return [Hash<String,Hash<Symbol,Float|Time>>] Format:
         
     | 
| 
      
 13 
     | 
    
         
            +
                #   {
         
     | 
| 
      
 14 
     | 
    
         
            +
                #      <acquirer id #1> => {
         
     | 
| 
      
 15 
     | 
    
         
            +
                #        zombie: <Boolean>,
         
     | 
| 
      
 16 
     | 
    
         
            +
                #        last_probe_time: <Time>,
         
     | 
| 
      
 17 
     | 
    
         
            +
                #        last_probe_score: <Numeric>
         
     | 
| 
      
 18 
     | 
    
         
            +
                #       },
         
     | 
| 
      
 19 
     | 
    
         
            +
                #      <acquirer id #2> => {
         
     | 
| 
      
 20 
     | 
    
         
            +
                #        zombie: <Boolean>,
         
     | 
| 
      
 21 
     | 
    
         
            +
                #        last_probe_time: <Time>,
         
     | 
| 
      
 22 
     | 
    
         
            +
                #        last_probe_score: <Numeric>
         
     | 
| 
      
 23 
     | 
    
         
            +
                #      },
         
     | 
| 
      
 24 
     | 
    
         
            +
                #     ...
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   }
         
     | 
| 
       27 
26 
     | 
    
         
             
                #
         
     | 
| 
       28 
27 
     | 
    
         
             
                # @api private
         
     | 
| 
       29 
28 
     | 
    
         
             
                # @since 1.9.0
         
     | 
| 
       30 
29 
     | 
    
         
             
                def acquirers(redis_client, zombie_ttl)
         
     | 
| 
       31 
30 
     | 
    
         
             
                  redis_client.with do |rconn|
         
     | 
| 
       32 
31 
     | 
    
         
             
                    rconn.call('HGETALL', RedisQueuedLocks::Resource::SWARM_KEY).tap do |swarm_acqs|
         
     | 
| 
      
 32 
     | 
    
         
            +
                      # @type var swarm_acqs: Hash[String,untyped]
         
     | 
| 
       33 
33 
     | 
    
         
             
                      swarm_acqs.transform_values! do |last_probe|
         
     | 
| 
      
 34 
     | 
    
         
            +
                        # @type var last_probe: String
         
     | 
| 
       34 
35 
     | 
    
         
             
                        last_probe_score = last_probe.to_f
         
     | 
| 
       35 
36 
     | 
    
         
             
                        last_probe_time = Time.at(last_probe_score)
         
     | 
| 
       36 
     | 
    
         
            -
                        zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000)
         
     | 
| 
      
 37 
     | 
    
         
            +
                        zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000.0)
         
     | 
| 
       37 
38 
     | 
    
         
             
                        is_zombie = last_probe_score < zombie_score
         
     | 
| 
       38 
39 
     | 
    
         
             
                        { zombie: is_zombie, last_probe_time:, last_probe_score: }
         
     | 
| 
       39 
40 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -8,14 +8,13 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem 
     | 
|
| 
       8 
8 
     | 
    
         
             
                # @parma zombie_ttl [Integer]
         
     | 
| 
       9 
9 
     | 
    
         
             
                # @param lock_scan_size [Integer]
         
     | 
| 
       10 
10 
     | 
    
         
             
                # @param queue_scan_size [Integer]
         
     | 
| 
       11 
     | 
    
         
            -
                # @return [
         
     | 
| 
       12 
     | 
    
         
            -
                #    
     | 
| 
      
 11 
     | 
    
         
            +
                # @return [Hash<Symbol,Boolean|Set<String>]] Format:
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   {
         
     | 
| 
       13 
13 
     | 
    
         
             
                #     ok: <Boolean>,
         
     | 
| 
       14 
14 
     | 
    
         
             
                #     deleted_zombie_hosts: <Set<String>>,
         
     | 
| 
       15 
     | 
    
         
            -
                #      
     | 
| 
      
 15 
     | 
    
         
            +
                #     deleted_zombie_acquirers: <Set<String>>,
         
     | 
| 
       16 
16 
     | 
    
         
             
                #     deleted_zombie_locks: <Set<String>>
         
     | 
| 
       17 
     | 
    
         
            -
                #    
     | 
| 
       18 
     | 
    
         
            -
                # ]
         
     | 
| 
      
 17 
     | 
    
         
            +
                #   }
         
     | 
| 
       19 
18 
     | 
    
         
             
                #
         
     | 
| 
       20 
19 
     | 
    
         
             
                # @api private
         
     | 
| 
       21 
20 
     | 
    
         
             
                # @since 1.9.0
         
     | 
| 
         @@ -30,7 +29,7 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem 
     | 
|
| 
       30 
29 
     | 
    
         
             
                    # Step 1:
         
     | 
| 
       31 
30 
     | 
    
         
             
                    #   calculate zombie score (the time marker that shows acquirers that
         
     | 
| 
       32 
31 
     | 
    
         
             
                    #   have not announced live probes for a long time)
         
     | 
| 
       33 
     | 
    
         
            -
                    zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000.0)
         
     | 
| 
       34 
33 
     | 
    
         | 
| 
       35 
34 
     | 
    
         
             
                    # Step 2: extract zombie acquirers from the swarm list
         
     | 
| 
       36 
35 
     | 
    
         
             
                    zombie_hosts = rconn.call('HGETALL', RedisQueuedLocks::Resource::SWARM_KEY)
         
     | 
| 
         @@ -39,30 +38,32 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem 
     | 
|
| 
       39 
38 
     | 
    
         
             
                    end
         
     | 
| 
       40 
39 
     | 
    
         | 
| 
       41 
40 
     | 
    
         
             
                    # Step X: exit if we have no any zombie acquirer
         
     | 
| 
       42 
     | 
    
         
            -
                    next  
     | 
| 
      
 41 
     | 
    
         
            +
                    next {
         
     | 
| 
       43 
42 
     | 
    
         
             
                      ok: true,
         
     | 
| 
       44 
43 
     | 
    
         
             
                      deleted_zombie_hosts: Set.new,
         
     | 
| 
       45 
44 
     | 
    
         
             
                      deleted_zombie_acquirers: Set.new,
         
     | 
| 
       46 
     | 
    
         
            -
                      deleted_zombie_locks: Set.new 
     | 
| 
       47 
     | 
    
         
            -
                     
     | 
| 
      
 45 
     | 
    
         
            +
                      deleted_zombie_locks: Set.new
         
     | 
| 
      
 46 
     | 
    
         
            +
                    } if zombie_hosts.empty?
         
     | 
| 
       48 
47 
     | 
    
         | 
| 
       49 
48 
     | 
    
         
             
                    # Step 3: find zombie locks held by zombies and delete them
         
     | 
| 
       50 
49 
     | 
    
         
             
                    # TODO: indexing (in order to prevent full database scan);
         
     | 
| 
       51 
50 
     | 
    
         
             
                    # NOTE: original redis does not support indexing so we need to use
         
     | 
| 
       52 
51 
     | 
    
         
             
                    #   internal data structers to simulate data indexing (such as sorted sets or lists);
         
     | 
| 
       53 
     | 
    
         
            -
                    zombie_locks = Set.new
         
     | 
| 
       54 
     | 
    
         
            -
                     
     | 
| 
      
 52 
     | 
    
         
            +
                    zombie_locks = Set.new #: Set[String]
         
     | 
| 
      
 53 
     | 
    
         
            +
                    zombie_acquirers = Set.new #: Set[String]
         
     | 
| 
       55 
54 
     | 
    
         | 
| 
       56 
55 
     | 
    
         
             
                    rconn.scan(
         
     | 
| 
       57 
56 
     | 
    
         
             
                      'MATCH', RedisQueuedLocks::Resource::LOCK_PATTERN, count: lock_scan_size
         
     | 
| 
       58 
57 
     | 
    
         
             
                    ) do |lock_key|
         
     | 
| 
       59 
     | 
    
         
            -
                       
     | 
| 
      
 58 
     | 
    
         
            +
                      acquirer_id, host_id = rconn.call('HMGET', lock_key, 'acq_id', 'hst_id')
         
     | 
| 
       60 
59 
     | 
    
         
             
                      if zombie_hosts.include?(host_id)
         
     | 
| 
       61 
60 
     | 
    
         
             
                        zombie_locks << lock_key
         
     | 
| 
       62 
     | 
    
         
            -
                         
     | 
| 
      
 61 
     | 
    
         
            +
                        zombie_acquirers << acquirer_id
         
     | 
| 
       63 
62 
     | 
    
         
             
                      end
         
     | 
| 
       64 
63 
     | 
    
         
             
                    end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    # NOTE: (steep) steep can't use <Set>s for splats
         
     | 
| 
      
 66 
     | 
    
         
            +
                    rconn.call('DEL', *zombie_locks) if zombie_locks.any? # steep:ignore
         
     | 
| 
       66 
67 
     | 
    
         | 
| 
       67 
68 
     | 
    
         
             
                    # Step 4: find zombie requests => and drop them
         
     | 
| 
       68 
69 
     | 
    
         
             
                    # TODO: indexing (in order to prevent full database scan);
         
     | 
| 
         @@ -71,8 +72,8 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem 
     | 
|
| 
       71 
72 
     | 
    
         
             
                    rconn.scan(
         
     | 
| 
       72 
73 
     | 
    
         
             
                      'MATCH', RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN, count: queue_scan_size
         
     | 
| 
       73 
74 
     | 
    
         
             
                    ) do |lock_queue|
         
     | 
| 
       74 
     | 
    
         
            -
                       
     | 
| 
       75 
     | 
    
         
            -
                        rconn.call('ZREM', lock_queue,  
     | 
| 
      
 75 
     | 
    
         
            +
                      zombie_acquirers.each do |zombie_acquirer|
         
     | 
| 
      
 76 
     | 
    
         
            +
                        rconn.call('ZREM', lock_queue, zombie_acquirer)
         
     | 
| 
       76 
77 
     | 
    
         
             
                      end
         
     | 
| 
       77 
78 
     | 
    
         
             
                    end
         
     | 
| 
       78 
79 
     | 
    
         | 
| 
         @@ -80,12 +81,12 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem 
     | 
|
| 
       80 
81 
     | 
    
         
             
                    rconn.call('HDEL', RedisQueuedLocks::Resource::SWARM_KEY, *zombie_hosts)
         
     | 
| 
       81 
82 
     | 
    
         | 
| 
       82 
83 
     | 
    
         
             
                    # Step 6: inform about deleted zombies
         
     | 
| 
       83 
     | 
    
         
            -
                     
     | 
| 
      
 84 
     | 
    
         
            +
                    {
         
     | 
| 
       84 
85 
     | 
    
         
             
                      ok: true,
         
     | 
| 
       85 
86 
     | 
    
         
             
                      deleted_zombie_hosts: zombie_hosts,
         
     | 
| 
       86 
     | 
    
         
            -
                       
     | 
| 
      
 87 
     | 
    
         
            +
                      deleted_zombie_acquirers: zombie_acquirers,
         
     | 
| 
       87 
88 
     | 
    
         
             
                      deleted_zombie_locks: zombie_locks
         
     | 
| 
       88 
     | 
    
         
            -
                     
     | 
| 
      
 89 
     | 
    
         
            +
                    }
         
     | 
| 
       89 
90 
     | 
    
         
             
                  end
         
     | 
| 
       90 
91 
     | 
    
         
             
                end
         
     | 
| 
       91 
92 
     | 
    
         
             
                # rubocop:enable Metrics/MethodLength
         
     | 
| 
         @@ -96,7 +97,7 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem 
     | 
|
| 
       96 
97 
     | 
    
         
             
              # @api private
         
     | 
| 
       97 
98 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       98 
99 
     | 
    
         
             
              def enabled?
         
     | 
| 
       99 
     | 
    
         
            -
                rql_client.config[ 
     | 
| 
      
 100 
     | 
    
         
            +
                rql_client.config['swarm.flush_zombies.enabled_for_swarm']
         
     | 
| 
       100 
101 
     | 
    
         
             
              end
         
     | 
| 
       101 
102 
     | 
    
         | 
| 
       102 
103 
     | 
    
         
             
              # @return [void]
         
     | 
| 
         @@ -105,11 +106,11 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem 
     | 
|
| 
       105 
106 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       106 
107 
     | 
    
         
             
              def swarm!
         
     | 
| 
       107 
108 
     | 
    
         
             
                @swarm_element = Ractor.new(
         
     | 
| 
       108 
     | 
    
         
            -
                  rql_client.config. 
     | 
| 
       109 
     | 
    
         
            -
                  rql_client.config[ 
     | 
| 
       110 
     | 
    
         
            -
                  rql_client.config[ 
     | 
| 
       111 
     | 
    
         
            -
                  rql_client.config[ 
     | 
| 
       112 
     | 
    
         
            -
                  rql_client.config[ 
     | 
| 
      
 109 
     | 
    
         
            +
                  rql_client.config.slice('swarm.flush_zombies.redis_config'),
         
     | 
| 
      
 110 
     | 
    
         
            +
                  rql_client.config['swarm.flush_zombies.zombie_ttl'],
         
     | 
| 
      
 111 
     | 
    
         
            +
                  rql_client.config['swarm.flush_zombies.zombie_lock_scan_size'],
         
     | 
| 
      
 112 
     | 
    
         
            +
                  rql_client.config['swarm.flush_zombies.zombie_queue_scan_size'],
         
     | 
| 
      
 113 
     | 
    
         
            +
                  rql_client.config['swarm.flush_zombies.zombie_flush_period']
         
     | 
| 
       113 
114 
     | 
    
         
             
                ) do |rc, z_ttl, z_lss, z_qss, z_fl_prd|
         
     | 
| 
       114 
115 
     | 
    
         
             
                  RedisQueuedLocks::Swarm::FlushZombies.swarm_loop do
         
     | 
| 
       115 
116 
     | 
    
         
             
                    Thread.new do
         
     | 
| 
         @@ -4,24 +4,25 @@ 
     | 
|
| 
       4 
4 
     | 
    
         
             
            # @since 1.9.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            class RedisQueuedLocks::Swarm::ProbeHosts < RedisQueuedLocks::Swarm::SwarmElement::Threaded
         
     | 
| 
       6 
6 
     | 
    
         
             
              class << self
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Returns a list of living hosts as a element command result. Result example:
         
     | 
| 
      
 8 
     | 
    
         
            +
                # {
         
     | 
| 
      
 9 
     | 
    
         
            +
                #   ok: <Boolean>,
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   result: {
         
     | 
| 
      
 11 
     | 
    
         
            +
                #     host_id1 <String> => score1 <String>,
         
     | 
| 
      
 12 
     | 
    
         
            +
                #     host_id2 <String> => score2 <String>,
         
     | 
| 
      
 13 
     | 
    
         
            +
                #     etc...
         
     | 
| 
      
 14 
     | 
    
         
            +
                #   }
         
     | 
| 
      
 15 
     | 
    
         
            +
                # }
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
       7 
17 
     | 
    
         
             
                # @param redis_client [RedisClient]
         
     | 
| 
       8 
18 
     | 
    
         
             
                # @param uniq_identity [String]
         
     | 
| 
       9 
     | 
    
         
            -
                # @return [
         
     | 
| 
       10 
     | 
    
         
            -
                #   RedisQueuedLocks::Data[
         
     | 
| 
       11 
     | 
    
         
            -
                #     ok: <Boolean>,
         
     | 
| 
       12 
     | 
    
         
            -
                #     result: {
         
     | 
| 
       13 
     | 
    
         
            -
                #       host_id1 <String> => score1 <String>,
         
     | 
| 
       14 
     | 
    
         
            -
                #       host_id2 <String> => score2 <String>,
         
     | 
| 
       15 
     | 
    
         
            -
                #       etc...
         
     | 
| 
       16 
     | 
    
         
            -
                #     }
         
     | 
| 
       17 
     | 
    
         
            -
                #   ]
         
     | 
| 
       18 
     | 
    
         
            -
                # ]
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @return [::Hash]
         
     | 
| 
       19 
20 
     | 
    
         
             
                #
         
     | 
| 
       20 
21 
     | 
    
         
             
                # @api private
         
     | 
| 
       21 
22 
     | 
    
         
             
                # @since 1.9.0
         
     | 
| 
       22 
23 
     | 
    
         
             
                def probe_hosts(redis_client, uniq_identity)
         
     | 
| 
       23 
24 
     | 
    
         
             
                  possible_hosts = RedisQueuedLocks::Resource.possible_host_identifiers(uniq_identity)
         
     | 
| 
       24 
     | 
    
         
            -
                  probed_hosts = {}
         
     | 
| 
      
 25 
     | 
    
         
            +
                  probed_hosts = {} #: Hash[String,Float]
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
       26 
27 
     | 
    
         
             
                  redis_client.with do |rconn|
         
     | 
| 
       27 
28 
     | 
    
         
             
                    possible_hosts.each do |host_id|
         
     | 
| 
         @@ -33,9 +34,9 @@ class RedisQueuedLocks::Swarm::ProbeHosts < RedisQueuedLocks::Swarm::SwarmElemen 
     | 
|
| 
       33 
34 
     | 
    
         
             
                      )
         
     | 
| 
       34 
35 
     | 
    
         
             
                      probed_hosts[host_id] = probe_score
         
     | 
| 
       35 
36 
     | 
    
         
             
                    end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                    RedisQueuedLocks::Data[ok: true, result: probed_hosts]
         
     | 
| 
       38 
37 
     | 
    
         
             
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  { ok: true, result: probed_hosts }
         
     | 
| 
       39 
40 
     | 
    
         
             
                end
         
     | 
| 
       40 
41 
     | 
    
         
             
              end
         
     | 
| 
       41 
42 
     | 
    
         | 
| 
         @@ -44,7 +45,7 @@ class RedisQueuedLocks::Swarm::ProbeHosts < RedisQueuedLocks::Swarm::SwarmElemen 
     | 
|
| 
       44 
45 
     | 
    
         
             
              # @api private
         
     | 
| 
       45 
46 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       46 
47 
     | 
    
         
             
              def enabled?
         
     | 
| 
       47 
     | 
    
         
            -
                rql_client.config[ 
     | 
| 
      
 48 
     | 
    
         
            +
                rql_client.config['swarm.probe_hosts.enabled_for_swarm']
         
     | 
| 
       48 
49 
     | 
    
         
             
              end
         
     | 
| 
       49 
50 
     | 
    
         | 
| 
       50 
51 
     | 
    
         
             
              # @return [Thread]
         
     | 
| 
         @@ -54,15 +55,15 @@ class RedisQueuedLocks::Swarm::ProbeHosts < RedisQueuedLocks::Swarm::SwarmElemen 
     | 
|
| 
       54 
55 
     | 
    
         
             
              def spawn_main_loop!
         
     | 
| 
       55 
56 
     | 
    
         
             
                Thread.new do
         
     | 
| 
       56 
57 
     | 
    
         
             
                  redis_client = RedisQueuedLocks::Swarm::RedisClientBuilder.build(
         
     | 
| 
       57 
     | 
    
         
            -
                    pooled: rql_client.config[ 
     | 
| 
       58 
     | 
    
         
            -
                    sentinel: rql_client.config[ 
     | 
| 
       59 
     | 
    
         
            -
                    config: rql_client.config[ 
     | 
| 
       60 
     | 
    
         
            -
                    pool_config: rql_client.config[ 
     | 
| 
      
 58 
     | 
    
         
            +
                    pooled: rql_client.config['swarm.probe_hosts.redis_config.pooled'],
         
     | 
| 
      
 59 
     | 
    
         
            +
                    sentinel: rql_client.config['swarm.probe_hosts.redis_config.sentinel'],
         
     | 
| 
      
 60 
     | 
    
         
            +
                    config: rql_client.config['swarm.probe_hosts.redis_config.config'],
         
     | 
| 
      
 61 
     | 
    
         
            +
                    pool_config: rql_client.config['swarm.probe_hosts.redis_config.pool_config']
         
     | 
| 
       61 
62 
     | 
    
         
             
                  )
         
     | 
| 
       62 
63 
     | 
    
         | 
| 
       63 
64 
     | 
    
         
             
                  loop do
         
     | 
| 
       64 
65 
     | 
    
         
             
                    RedisQueuedLocks::Swarm::ProbeHosts.probe_hosts(redis_client, rql_client.uniq_identity)
         
     | 
| 
       65 
     | 
    
         
            -
                    sleep(rql_client.config[ 
     | 
| 
      
 66 
     | 
    
         
            +
                    sleep(rql_client.config['swarm.probe_hosts.probe_period'])
         
     | 
| 
       66 
67 
     | 
    
         
             
                  end
         
     | 
| 
       67 
68 
     | 
    
         
             
                end
         
     | 
| 
       68 
69 
     | 
    
         
             
              end
         
     | 
| 
         @@ -7,7 +7,7 @@ module RedisQueuedLocks::Swarm::RedisClientBuilder 
     | 
|
| 
       7 
7 
     | 
    
         
             
                # @option pooled [Boolean]
         
     | 
| 
       8 
8 
     | 
    
         
             
                # @option sentinel [Boolean]
         
     | 
| 
       9 
9 
     | 
    
         
             
                # @option config [Hash]
         
     | 
| 
       10 
     | 
    
         
            -
                # @return [RedisClient]
         
     | 
| 
      
 10 
     | 
    
         
            +
                # @return [RedisClient|RedisClient::Pooled]
         
     | 
| 
       11 
11 
     | 
    
         
             
                #
         
     | 
| 
       12 
12 
     | 
    
         
             
                # @api private
         
     | 
| 
       13 
13 
     | 
    
         
             
                # @since 1.9.0
         
     | 
| 
         @@ -28,7 +28,7 @@ module RedisQueuedLocks::Swarm::RedisClientBuilder 
     | 
|
| 
       28 
28 
     | 
    
         
             
                private
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                # @param config [Hash]
         
     | 
| 
       31 
     | 
    
         
            -
                # @return [RedisClient:: 
     | 
| 
      
 31 
     | 
    
         
            +
                # @return [RedisClient::SentinelConfig]
         
     | 
| 
       32 
32 
     | 
    
         
             
                #
         
     | 
| 
       33 
33 
     | 
    
         
             
                # @api private
         
     | 
| 
       34 
34 
     | 
    
         
             
                # @since 1.9.0
         
     | 
| 
         @@ -47,7 +47,7 @@ module RedisQueuedLocks::Swarm::RedisClientBuilder 
     | 
|
| 
       47 
47 
     | 
    
         | 
| 
       48 
48 
     | 
    
         
             
                # @param redis_config [ReidsClient::Config]
         
     | 
| 
       49 
49 
     | 
    
         
             
                # @param pool_config [Hash]
         
     | 
| 
       50 
     | 
    
         
            -
                # @return [RedisClient]
         
     | 
| 
      
 50 
     | 
    
         
            +
                # @return [RedisClient::Pooled]
         
     | 
| 
       51 
51 
     | 
    
         
             
                #
         
     | 
| 
       52 
52 
     | 
    
         
             
                # @api private
         
     | 
| 
       53 
53 
     | 
    
         
             
                # @since 1.9.0
         
     | 
| 
         @@ -43,11 +43,11 @@ class RedisQueuedLocks::Swarm::Supervisor 
     | 
|
| 
       43 
43 
     | 
    
         
             
                @observable = observable
         
     | 
| 
       44 
44 
     | 
    
         
             
                @visor = Thread.new do
         
     | 
| 
       45 
45 
     | 
    
         
             
                  loop do
         
     | 
| 
       46 
     | 
    
         
            -
                    yield rescue nil # TODO 
     | 
| 
       47 
     | 
    
         
            -
                    sleep(rql_client.config[ 
     | 
| 
      
 46 
     | 
    
         
            +
                    yield rescue nil # TODO: (CHECK): may be we need to process exceptions here
         
     | 
| 
      
 47 
     | 
    
         
            +
                    sleep(rql_client.config['swarm.supervisor.liveness_probing_period'])
         
     | 
| 
       48 
48 
     | 
    
         
             
                  end
         
     | 
| 
       49 
49 
     | 
    
         
             
                end
         
     | 
| 
       50 
     | 
    
         
            -
                # NOTE: need to give a timespot to initialize visor thread;
         
     | 
| 
      
 50 
     | 
    
         
            +
                # NOTE: need to give a timespot to initialize a visor thread;
         
     | 
| 
       51 
51 
     | 
    
         
             
                sleep(0.1)
         
     | 
| 
       52 
52 
     | 
    
         
             
              end
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
         @@ -56,7 +56,11 @@ class RedisQueuedLocks::Swarm::Supervisor 
     | 
|
| 
       56 
56 
     | 
    
         
             
              # @api private
         
     | 
| 
       57 
57 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       58 
58 
     | 
    
         
             
              def running?
         
     | 
| 
       59 
     | 
    
         
            -
                 
     | 
| 
      
 59 
     | 
    
         
            +
                # NOTE:
         
     | 
| 
      
 60 
     | 
    
         
            +
                #   steep can not understand that visor.alive? is invoked on
         
     | 
| 
      
 61 
     | 
    
         
            +
                #   `::Thread` here (not on `::Thread | nil` after the `nil`-check);
         
     | 
| 
      
 62 
     | 
    
         
            +
                #   so we need to ignore this check temporary and wait the best future :)
         
     | 
| 
      
 63 
     | 
    
         
            +
                visor != nil && visor.alive? # steep:ignore
         
     | 
| 
       60 
64 
     | 
    
         
             
              end
         
     | 
| 
       61 
65 
     | 
    
         | 
| 
       62 
66 
     | 
    
         
             
              # @return [void]
         
     | 
| 
         @@ -64,7 +68,11 @@ class RedisQueuedLocks::Swarm::Supervisor 
     | 
|
| 
       64 
68 
     | 
    
         
             
              # @api private
         
     | 
| 
       65 
69 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       66 
70 
     | 
    
         
             
              def stop!
         
     | 
| 
       67 
     | 
    
         
            -
                 
     | 
| 
      
 71 
     | 
    
         
            +
                # NOTE:
         
     | 
| 
      
 72 
     | 
    
         
            +
                #   steep can not understand that visor.kill is invoked on
         
     | 
| 
      
 73 
     | 
    
         
            +
                #   `::Thread` here (not on `::Thread | nil` after the `nil`-check);
         
     | 
| 
      
 74 
     | 
    
         
            +
                #   so we need to ignore this check temporary and wait the best future :)
         
     | 
| 
      
 75 
     | 
    
         
            +
                visor.kill if running? # steep:ignore
         
     | 
| 
       68 
76 
     | 
    
         
             
                @visor = nil
         
     | 
| 
       69 
77 
     | 
    
         
             
                @observable = nil
         
     | 
| 
       70 
78 
     | 
    
         
             
              end
         
     | 
| 
         @@ -74,9 +82,14 @@ class RedisQueuedLocks::Swarm::Supervisor 
     | 
|
| 
       74 
82 
     | 
    
         
             
              # @api private
         
     | 
| 
       75 
83 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       76 
84 
     | 
    
         
             
              def status
         
     | 
| 
      
 85 
     | 
    
         
            +
                # NOTE:
         
     | 
| 
      
 86 
     | 
    
         
            +
                #   steep can not understand that thread_state(visor) is invoked on
         
     | 
| 
      
 87 
     | 
    
         
            +
                #   `::Thread` here (not on `::Thread | nil` after the `nil`-check);
         
     | 
| 
      
 88 
     | 
    
         
            +
                #   so we need to ignore this check temporary and wait the best future :)
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
       77 
90 
     | 
    
         
             
                {
         
     | 
| 
       78 
91 
     | 
    
         
             
                  running: running?,
         
     | 
| 
       79 
     | 
    
         
            -
                  state: (visor == nil) ? 'non_initialized' : thread_state(visor),
         
     | 
| 
      
 92 
     | 
    
         
            +
                  state: (visor == nil) ? 'non_initialized' : thread_state(visor), # steep:ignore
         
     | 
| 
       80 
93 
     | 
    
         
             
                  observable: (observable == nil) ? 'non_initialized' : 'initialized'
         
     | 
| 
       81 
94 
     | 
    
         
             
                }
         
     | 
| 
       82 
95 
     | 
    
         
             
              end
         
     | 
| 
         @@ -25,6 +25,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       25 
25 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       26 
26 
     | 
    
         
             
              attr_reader :sync
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
      
 28 
     | 
    
         
            +
              # @param rql_client [RedisQueuedLocks::Client]
         
     | 
| 
       28 
29 
     | 
    
         
             
              # @return [void]
         
     | 
| 
       29 
30 
     | 
    
         
             
              #
         
     | 
| 
       30 
31 
     | 
    
         
             
              # @api private
         
     | 
| 
         @@ -80,12 +81,12 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       80 
81 
     | 
    
         
             
              #
         
     | 
| 
       81 
82 
     | 
    
         
             
              # @api private
         
     | 
| 
       82 
83 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       83 
     | 
    
         
            -
              def enabled?
         
     | 
| 
      
 84 
     | 
    
         
            +
              def enabled? # steep:ignore
         
     | 
| 
       84 
85 
     | 
    
         
             
                # NOTE: provide an <is enabled> logic here by analyzing the redis queued locks config.
         
     | 
| 
       85 
86 
     | 
    
         
             
              end
         
     | 
| 
       86 
87 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
              # @return [Hash<Symbol,Boolean|Hash<Symbol,String|Boolean>>]
         
     | 
| 
       88 
     | 
    
         
            -
              #    
     | 
| 
      
 88 
     | 
    
         
            +
              # @return [Hash<Symbol,Boolean|Hash<Symbol,String|Boolean>>] Format:
         
     | 
| 
      
 89 
     | 
    
         
            +
              #   {
         
     | 
| 
       89 
90 
     | 
    
         
             
              #     enabled: <Boolean>,
         
     | 
| 
       90 
91 
     | 
    
         
             
              #     ractor: {
         
     | 
| 
       91 
92 
     | 
    
         
             
              #       running: <Boolean>,
         
     | 
| 
         @@ -102,16 +103,16 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       102 
103 
     | 
    
         
             
              def status
         
     | 
| 
       103 
104 
     | 
    
         
             
                sync.synchronize do
         
     | 
| 
       104 
105 
     | 
    
         
             
                  ractor_running = swarmed__alive?
         
     | 
| 
       105 
     | 
    
         
            -
                  ractor_state = swarmed? ? ractor_status(swarm_element) : 'non_initialized'
         
     | 
| 
      
 106 
     | 
    
         
            +
                  ractor_state = swarmed? ? ractor_status(swarm_element) : 'non_initialized' # steep:ignore
         
     | 
| 
       106 
107 
     | 
    
         | 
| 
       107 
     | 
    
         
            -
                  main_loop_running = nil
         
     | 
| 
       108 
     | 
    
         
            -
                  main_loop_state = nil
         
     | 
| 
       109 
108 
     | 
    
         
             
                  begin
         
     | 
| 
       110 
109 
     | 
    
         
             
                    main_loop_running = swarmed__running?
         
     | 
| 
      
 110 
     | 
    
         
            +
                    # steep:ignore:start
         
     | 
| 
       111 
111 
     | 
    
         
             
                    main_loop_state =
         
     | 
| 
       112 
112 
     | 
    
         
             
                      main_loop_running ? swarm_loop__status[:main_loop][:state] : 'non_initialized'
         
     | 
| 
      
 113 
     | 
    
         
            +
                    # steep:ignore:end
         
     | 
| 
       113 
114 
     | 
    
         
             
                  rescue Ractor::ClosedError
         
     | 
| 
       114 
     | 
    
         
            -
                    # NOTE: it can happend when you  
     | 
| 
      
 115 
     | 
    
         
            +
                    # NOTE: it can happend when you running RedisQueuedLocks::Swarm#deswarm!
         
     | 
| 
       115 
116 
     | 
    
         
             
                    main_loop_running = false
         
     | 
| 
       116 
117 
     | 
    
         
             
                    main_loop_state = 'non_initialized'
         
     | 
| 
       117 
118 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -160,6 +161,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       160 
161 
     | 
    
         
             
                #   to provide better code readability (it is placed next to the method inside
         
     | 
| 
       161 
162 
     | 
    
         
             
                #   wich it should be called (see #swarm!)). That's why some rubocop cops are disabled.
         
     | 
| 
       162 
163 
     | 
    
         | 
| 
      
 164 
     | 
    
         
            +
                # @type var main_loop: Thread?
         
     | 
| 
       163 
165 
     | 
    
         
             
                main_loop = nil
         
     | 
| 
       164 
166 
     | 
    
         | 
| 
       165 
167 
     | 
    
         
             
                loop do
         
     | 
| 
         @@ -167,24 +169,24 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       167 
169 
     | 
    
         | 
| 
       168 
170 
     | 
    
         
             
                  case command
         
     | 
| 
       169 
171 
     | 
    
         
             
                  when :status
         
     | 
| 
       170 
     | 
    
         
            -
                    main_loop_alive = main_loop != nil && main_loop.alive?
         
     | 
| 
      
 172 
     | 
    
         
            +
                    main_loop_alive = main_loop != nil && main_loop.alive? # steep:ignore
         
     | 
| 
       171 
173 
     | 
    
         
             
                    main_loop_state =
         
     | 
| 
       172 
174 
     | 
    
         
             
                      if main_loop == nil
         
     | 
| 
       173 
175 
     | 
    
         
             
                        'non_initialized'
         
     | 
| 
       174 
176 
     | 
    
         
             
                      else
         
     | 
| 
       175 
     | 
    
         
            -
                        #  
     | 
| 
      
 177 
     | 
    
         
            +
                        # @type var main_loop: Thread
         
     | 
| 
       176 
178 
     | 
    
         
             
                        RedisQueuedLocks::Utilities.thread_state(main_loop)
         
     | 
| 
       177 
179 
     | 
    
         
             
                      end
         
     | 
| 
       178 
180 
     | 
    
         
             
                    Ractor.yield({ main_loop: { alive: main_loop_alive, state: main_loop_state } })
         
     | 
| 
       179 
181 
     | 
    
         
             
                  when :is_active
         
     | 
| 
       180 
     | 
    
         
            -
                    Ractor.yield(main_loop != nil && main_loop.alive?)
         
     | 
| 
      
 182 
     | 
    
         
            +
                    Ractor.yield(main_loop != nil && main_loop.alive?) # steep:ignore
         
     | 
| 
       181 
183 
     | 
    
         
             
                  when :start
         
     | 
| 
       182 
     | 
    
         
            -
                    main_loop.kill if main_loop != nil
         
     | 
| 
      
 184 
     | 
    
         
            +
                    main_loop.kill if main_loop != nil # steep:ignore
         
     | 
| 
       183 
185 
     | 
    
         
             
                    main_loop = yield # REFERENCE: `main_loop_spawner.call`
         
     | 
| 
       184 
186 
     | 
    
         
             
                  when :stop
         
     | 
| 
       185 
     | 
    
         
            -
                    main_loop.kill if main_loop != nil
         
     | 
| 
      
 187 
     | 
    
         
            +
                    main_loop.kill if main_loop != nil # steep:ignore
         
     | 
| 
       186 
188 
     | 
    
         
             
                  when :kill
         
     | 
| 
       187 
     | 
    
         
            -
                    main_loop.kill if main_loop != nil
         
     | 
| 
      
 189 
     | 
    
         
            +
                    main_loop.kill if main_loop != nil # steep:ignore
         
     | 
| 
       188 
190 
     | 
    
         
             
                    exit
         
     | 
| 
       189 
191 
     | 
    
         
             
                  end
         
     | 
| 
       190 
192 
     | 
    
         
             
                end
         
     | 
| 
         @@ -212,7 +214,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       212 
214 
     | 
    
         
             
              # @api private
         
     | 
| 
       213 
215 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       214 
216 
     | 
    
         
             
              def swarmed__alive?
         
     | 
| 
       215 
     | 
    
         
            -
                swarm_element != nil && ractor_alive?(swarm_element)
         
     | 
| 
      
 217 
     | 
    
         
            +
                swarm_element != nil && ractor_alive?(swarm_element) # steep:ignore
         
     | 
| 
       216 
218 
     | 
    
         
             
              end
         
     | 
| 
       217 
219 
     | 
    
         | 
| 
       218 
220 
     | 
    
         
             
              # @return [Boolean]
         
     | 
| 
         @@ -220,7 +222,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       220 
222 
     | 
    
         
             
              # @api private
         
     | 
| 
       221 
223 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       222 
224 
     | 
    
         
             
              def swarmed__dead?
         
     | 
| 
       223 
     | 
    
         
            -
                swarm_element != nil && !ractor_alive?(swarm_element)
         
     | 
| 
      
 225 
     | 
    
         
            +
                swarm_element != nil && !ractor_alive?(swarm_element) # steep:ignore
         
     | 
| 
       224 
226 
     | 
    
         
             
              end
         
     | 
| 
       225 
227 
     | 
    
         | 
| 
       226 
228 
     | 
    
         
             
              # @return [Boolean]
         
     | 
| 
         @@ -228,7 +230,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       228 
230 
     | 
    
         
             
              # @api private
         
     | 
| 
       229 
231 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       230 
232 
     | 
    
         
             
              def swarmed__running?
         
     | 
| 
       231 
     | 
    
         
            -
                swarm_element != nil && ractor_alive?(swarm_element) && swarm_loop__is_active
         
     | 
| 
      
 233 
     | 
    
         
            +
                swarm_element != nil && ractor_alive?(swarm_element) && swarm_loop__is_active # steep:ignore
         
     | 
| 
       232 
234 
     | 
    
         
             
              end
         
     | 
| 
       233 
235 
     | 
    
         | 
| 
       234 
236 
     | 
    
         
             
              # @return [Boolean]
         
     | 
| 
         @@ -236,7 +238,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       236 
238 
     | 
    
         
             
              # @api private
         
     | 
| 
       237 
239 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       238 
240 
     | 
    
         
             
              def swarmed__stopped?
         
     | 
| 
       239 
     | 
    
         
            -
                swarm_element != nil && ractor_alive?(swarm_element) && !swarm_loop__is_active
         
     | 
| 
      
 241 
     | 
    
         
            +
                swarm_element != nil && ractor_alive?(swarm_element) && !swarm_loop__is_active # steep:ignore
         
     | 
| 
       240 
242 
     | 
    
         
             
              end
         
     | 
| 
       241 
243 
     | 
    
         | 
| 
       242 
244 
     | 
    
         
             
              # @return [Boolean]
         
     | 
| 
         @@ -244,7 +246,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated 
     | 
|
| 
       244 
246 
     | 
    
         
             
              # @api private
         
     | 
| 
       245 
247 
     | 
    
         
             
              # @since 1.9.0
         
     | 
| 
       246 
248 
     | 
    
         
             
              def swarm_loop__is_active
         
     | 
| 
       247 
     | 
    
         
            -
                return if idle? || swarmed__dead?
         
     | 
| 
      
 249 
     | 
    
         
            +
                return false if idle? || swarmed__dead?
         
     | 
| 
       248 
250 
     | 
    
         
             
                sync.synchronize { swarm_element.send(:is_active).take }
         
     | 
| 
       249 
251 
     | 
    
         
             
              end
         
     | 
| 
       250 
252 
     | 
    
         |