Class: RedisQueuedLocks::Swarm::FlushZombies Private
- Inherits:
-
SwarmElement::Isolated
- Object
- SwarmElement::Isolated
- RedisQueuedLocks::Swarm::FlushZombies
- Defined in:
- lib/redis_queued_locks/swarm/flush_zombies.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Constant Summary
Constants included from Utilities
Utilities::RACTOR_LIVENESS_PATTERN, Utilities::RACTOR_STATUS_PATTERN, Utilities::RUBY_OVER_4
Instance Attribute Summary
Attributes inherited from SwarmElement::Isolated
#rql_client, #swarm_element, #sync
Class Method Summary collapse
-
.flush_zombies(redis_client, zombie_ttl, lock_scan_size, queue_scan_size) ⇒ Hash<Symbol,Boolean|Set<String>]
private
rubocop:disable Metrics/MethodLength.
Instance Method Summary collapse
- #enabled? ⇒ Boolean private
- #swarm! ⇒ void private
Methods inherited from SwarmElement::Isolated
#initialize, #reswarm_if_dead!, #status, swarm_loop, #try_kill!, #try_swarm!
Methods included from Utilities
clock_gettime, ractor_alive?, ractor_status, ruby_over_4?, run_non_critical, thread_state
Constructor Details
This class inherits a constructor from RedisQueuedLocks::Swarm::SwarmElement::Isolated
Class Method Details
.flush_zombies(redis_client, zombie_ttl, lock_scan_size, queue_scan_size) ⇒ Hash<Symbol,Boolean|Set<String>]
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
rubocop:disable Metrics/MethodLength
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/redis_queued_locks/swarm/flush_zombies.rb', line 22 def flush_zombies( redis_client, zombie_ttl, lock_scan_size, queue_scan_size ) redis_client.with do |rconn| # Step 1: # calculate zombie score (the time marker that shows acquirers that # have not announced live probes for a long time) zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000.0) # Step 2: extract zombie acquirers from the swarm list zombie_hosts = rconn.call('HGETALL', RedisQueuedLocks::Resource::SWARM_KEY) zombie_hosts = zombie_hosts.each_with_object(Set.new) do |(hst_id, ts), zombies| (zombies << hst_id) if (zombie_score > ts.to_f) end # Step X: exit if we have no any zombie acquirer next { ok: true, deleted_zombie_hosts: Set.new, deleted_zombie_acquirers: Set.new, deleted_zombie_locks: Set.new } if zombie_hosts.empty? # Step 3: find zombie locks held by zombies and delete them # TODO: indexing (in order to prevent full database scan); # NOTE: original redis does not support indexing so we need to use # internal data structers to simulate data indexing (such as sorted sets or lists); zombie_locks = Set.new #: Set[String] zombie_acquirers = Set.new #: Set[String] rconn.scan( 'MATCH', RedisQueuedLocks::Resource::LOCK_PATTERN, count: lock_scan_size ) do |lock_key| acquirer_id, host_id = rconn.call('HMGET', lock_key, 'acq_id', 'hst_id') if zombie_hosts.include?(host_id) zombie_locks << lock_key zombie_acquirers << acquirer_id end end # NOTE: (steep) steep can't use <Set>s for splats rconn.call('DEL', *zombie_locks) if zombie_locks.any? # steep:ignore # Step 4: find zombie requests => and drop them # TODO: indexing (in order to prevent full database scan); # NOTE: original redis does not support indexing so we need to use # internal data structers to simulate data indexing (such as sorted sets or lists); rconn.scan( 'MATCH', RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN, count: queue_scan_size ) do |lock_queue| zombie_acquirers.each do |zombie_acquirer| rconn.call('ZREM', lock_queue, zombie_acquirer) end end # Step 5: drop zombies from the swarm rconn.call('HDEL', RedisQueuedLocks::Resource::SWARM_KEY, *zombie_hosts) # Step 6: inform about deleted zombies { ok: true, deleted_zombie_hosts: zombie_hosts, deleted_zombie_acquirers: zombie_acquirers, deleted_zombie_locks: zombie_locks } end end |
Instance Method Details
#enabled? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
99 100 101 |
# File 'lib/redis_queued_locks/swarm/flush_zombies.rb', line 99 def enabled? rql_client.config['swarm.flush_zombies.enabled_for_swarm'] end |
#swarm! ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/redis_queued_locks/swarm/flush_zombies.rb', line 107 def swarm! @swarm_element = Ractor.new( rql_client.config.slice('swarm.flush_zombies.redis_config'), rql_client.config['swarm.flush_zombies.zombie_ttl'], rql_client.config['swarm.flush_zombies.zombie_lock_scan_size'], rql_client.config['swarm.flush_zombies.zombie_queue_scan_size'], rql_client.config['swarm.flush_zombies.zombie_flush_period'] ) do |rc, z_ttl, z_lss, z_qss, z_fl_prd| RedisQueuedLocks::Swarm::FlushZombies.swarm_loop do Thread.new do redis_client = RedisQueuedLocks::Swarm::RedisClientBuilder.build( pooled: rc['pooled'], sentinel: rc['sentinel'], config: rc['config'], pool_config: rc['pool_config'] ) loop do RedisQueuedLocks::Swarm::FlushZombies.flush_zombies( redis_client, z_ttl, z_lss, z_qss ) sleep(z_fl_prd) end end end end end |