redis_queued_locks 1.12.0 → 1.13.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 +4 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +42 -5
- data/LICENSE.txt +1 -1
- data/README.md +231 -203
- data/Rakefile +12 -4
- data/Steepfile +16 -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 -13
- 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 +43 -20
- data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock.rb +69 -42
- 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 +23 -18
- data/lib/redis_queued_locks/{acquier → acquirer}/release_lock.rb +25 -19
- data/lib/redis_queued_locks/acquirer.rb +18 -0
- data/lib/redis_queued_locks/client.rb +164 -254
- data/lib/redis_queued_locks/config/dsl.rb +94 -0
- data/lib/redis_queued_locks/config.rb +231 -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/lock.rb +4 -2
- data/lib/redis_queued_locks/utilities.rb +2 -2
- data/lib/redis_queued_locks/version.rb +2 -2
- data/lib/redis_queued_locks.rb +2 -2
- data/rbs_collection.lock.yaml +40 -0
- data/rbs_collection.yaml +16 -0
- data/redis_queued_locks.gemspec +22 -23
- data/sig/manifest.yml +7 -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 +51 -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/client.rbs +195 -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 +11 -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 +96 -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
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since [1.13.0]
|
5
|
+
module RedisQueuedLocks::Config::DSL
|
6
|
+
# @api private
|
7
|
+
# @since [1.13.0]
|
8
|
+
module ClassMethods
|
9
|
+
# NOTE:
|
10
|
+
# 1. Style/DefWithParentheses rubocop's cop incorrectly drops `()` from method definition
|
11
|
+
# and breaks ruby code syntax. So this cop is disabled here;
|
12
|
+
# 2. attr_reader is not used cuz `steep` can't understand it form inside the class where
|
13
|
+
# the current module is mixed;
|
14
|
+
#
|
15
|
+
# @return [Hash<String,Block>]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since [1.13.0]
|
19
|
+
def config_setters()= @config_setters # rubocop:disable Style/DefWithParentheses
|
20
|
+
|
21
|
+
# NOTE:
|
22
|
+
# 1. Style/DefWithParentheses rubocop's cop incorrectly drops `()` from method definition
|
23
|
+
# and breaks ruby code syntax. So this cop is disabled here;
|
24
|
+
# 2. attr_reader is not used cuz `steep` can't understand it form inside the class where
|
25
|
+
# the current module is mixed;
|
26
|
+
#
|
27
|
+
# @return [Hash<String,Block>]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
# @since [1.13.0]
|
31
|
+
def config_validators()= @config_validators # rubocop:disable Style/DefWithParentheses
|
32
|
+
|
33
|
+
# @param config_key [String]
|
34
|
+
# @param validator [Block]
|
35
|
+
# @return [Bool]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @since [1.13.0]
|
39
|
+
def validate(config_key, &validator)
|
40
|
+
config_validators[config_key] = validator
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param config_key [String]
|
44
|
+
# @param config_value [Any]
|
45
|
+
# @return [void]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
# @since [1.13.0]
|
49
|
+
def setting(config_key, config_value)
|
50
|
+
config_setters[config_key] = proc do |config|
|
51
|
+
config[config_key] = config_value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module InstanceMethods
|
57
|
+
# @return [Hash<String,Blcok>]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
# @since [1.13.0]
|
61
|
+
def config_setters
|
62
|
+
self.class.config_setters # steep:ignore
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Hash<String,Blcok>]
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
# @since [1.13.0]
|
69
|
+
def config_validators
|
70
|
+
self.class.config_validators # steep:ignore
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class << self
|
75
|
+
# @param child_klass [Class]
|
76
|
+
# @return [void]
|
77
|
+
#
|
78
|
+
# @api private
|
79
|
+
# @since [1.13.0]
|
80
|
+
def included(child_klass)
|
81
|
+
child_klass.instance_variable_set(
|
82
|
+
:@config_setters,
|
83
|
+
{} #: RedisQueuedLocks::Config::DSL::configSetters
|
84
|
+
)
|
85
|
+
child_klass.instance_variable_set(
|
86
|
+
:@config_validators,
|
87
|
+
{} #: RedisQueuedLocks::Config::DSL::configValidators
|
88
|
+
)
|
89
|
+
child_klass.extend(ClassMethods)
|
90
|
+
child_klass.include(InstanceMethods)
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since [1.13.0]
|
5
|
+
# rubocop:disable Metrics/ClassLength
|
6
|
+
class RedisQueuedLocks::Config
|
7
|
+
require_relative 'config/dsl'
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
# @since [1.13.0]
|
11
|
+
include DSL
|
12
|
+
|
13
|
+
setting('retry_count', 3)
|
14
|
+
setting('retry_delay', 200) # NOTE: in milliseconds)
|
15
|
+
setting('retry_jitter', 25) # NOTE: in milliseconds)
|
16
|
+
setting('try_to_lock_timeout', 10) # NOTE: in seconds)
|
17
|
+
setting('default_lock_ttl', 5_000) # NOTE: in milliseconds)
|
18
|
+
setting('default_queue_ttl', 15) # NOTE: in seconds)
|
19
|
+
setting('detailed_acq_timeout_error', false)
|
20
|
+
setting('lock_release_batch_size', 100)
|
21
|
+
setting('key_extraction_batch_size', 500)
|
22
|
+
setting('instrumenter', RedisQueuedLocks::Instrument::VoidNotifier)
|
23
|
+
setting('uniq_identifier', -> { RedisQueuedLocks::Resource.calc_uniq_identity })
|
24
|
+
setting('logger', RedisQueuedLocks::Logging::VoidLogger)
|
25
|
+
setting('log_lock_try', false)
|
26
|
+
setting('dead_request_ttl', 1 * 24 * 60 * 60 * 1000) # NOTE: 1 day in milliseconds)
|
27
|
+
setting('is_timed_by_default', false)
|
28
|
+
setting('default_conflict_strategy', :wait_for_lock)
|
29
|
+
setting('default_access_strategy', :queued)
|
30
|
+
setting('log_sampling_enabled', false)
|
31
|
+
setting('log_sampling_percent', 15)
|
32
|
+
setting('log_sampler', RedisQueuedLocks::Logging::Sampler)
|
33
|
+
setting('instr_sampling_enabled', false)
|
34
|
+
setting('instr_sampling_percent', 15)
|
35
|
+
setting('instr_sampler', RedisQueuedLocks::Instrument::Sampler)
|
36
|
+
setting('swarm.auto_swarm', false)
|
37
|
+
setting('swarm.supervisor.liveness_probing_period', 2) # NOTE: in seconds)
|
38
|
+
setting('swarm.probe_hosts.enabled_for_swarm', true)
|
39
|
+
setting('swarm.probe_hosts.probe_period', 2) # NOTE: in seconds)
|
40
|
+
setting('swarm.probe_hosts.redis_config.sentinel', false)
|
41
|
+
setting('swarm.probe_hosts.redis_config.pooled', false)
|
42
|
+
setting('swarm.probe_hosts.redis_config.config', {})
|
43
|
+
setting('swarm.probe_hosts.redis_config.pool_config', {})
|
44
|
+
setting('swarm.flush_zombies.enabled_for_swarm', true)
|
45
|
+
setting('swarm.flush_zombies.zombie_ttl', 15_000) # NOTE: in milliseconds)
|
46
|
+
setting('swarm.flush_zombies.zombie_lock_scan_size', 500)
|
47
|
+
setting('swarm.flush_zombies.zombie_queue_scan_size', 500)
|
48
|
+
setting('swarm.flush_zombies.zombie_flush_period', 10)
|
49
|
+
setting('swarm.flush_zombies.redis_config.sentinel', false)
|
50
|
+
setting('swarm.flush_zombies.redis_config.pooled', false)
|
51
|
+
setting('swarm.flush_zombies.redis_config.config', {})
|
52
|
+
setting('swarm.flush_zombies.redis_config.pool_config', {})
|
53
|
+
|
54
|
+
validate('swarm.auto_swarm') { |val| val == true || val == false }
|
55
|
+
validate('swarm.supervisor.liveness_probing_period') { |val| val.is_a?(Integer) }
|
56
|
+
|
57
|
+
validate('swarm.probe_hosts.enabled_for_swarm') { |val| val == true || val == false }
|
58
|
+
validate('swarm.probe_hosts.redis_config.sentinel') { |val| val == true || val == false }
|
59
|
+
validate('swarm.probe_hosts.redis_config.pooled') { |val| val == true || val == false }
|
60
|
+
validate('swarm.probe_hosts.redis_config.config') { |val| val.is_a?(Hash) }
|
61
|
+
validate('swarm.probe_hosts.redis_config.pool_config') { |val| val.is_a?(Hash) }
|
62
|
+
validate('swarm.probe_hosts.probe_period') { |val| val.is_a?(Integer) }
|
63
|
+
|
64
|
+
validate('swarm.flush_zombies.enabled_for_swarm') { |val| val == true || val == false }
|
65
|
+
validate('swarm.flush_zombies.redis_config.sentinel') { |val| val == true || val == false }
|
66
|
+
validate('swarm.flush_zombies.redis_config.pooled') { |val| val == true || val == false }
|
67
|
+
validate('swarm.flush_zombies.redis_config.config') { |val| val.is_a?(Hash) }
|
68
|
+
validate('swarm.flush_zombies.redis_config.pool_config') { |val| val.is_a?(Hash) }
|
69
|
+
validate('swarm.flush_zombies.zombie_ttl') { |val| val.is_a?(Integer) }
|
70
|
+
validate('swarm.flush_zombies.zombie_lock_scan_size') { |val| val.is_a?(Integer) }
|
71
|
+
validate('swarm.flush_zombies.zombie_queue_scan_size') { |val| val.is_a?(Integer) }
|
72
|
+
validate('swarm.flush_zombies.zombie_flush_period') { |val| val.is_a?(Integer) }
|
73
|
+
|
74
|
+
validate('retry_count') { |val| val == nil || (val.is_a?(Integer) && val >= 0) }
|
75
|
+
validate('retry_delay') { |val| val.is_a?(Integer) && val >= 0 }
|
76
|
+
validate('retry_jitter') { |val| val.is_a?(Integer) && val >= 0 }
|
77
|
+
validate('try_to_lock_timeout') { |val| val == nil || (val.is_a?(Integer) && val >= 0) }
|
78
|
+
validate('default_lock_tt') { |val| val.is_a?(Integer) }
|
79
|
+
validate('default_queue_ttl') { |val| val.is_a?(Integer) }
|
80
|
+
validate('detailed_acq_timeout_error') { |val| val == true || val == false }
|
81
|
+
validate('lock_release_batch_size') { |val| val.is_a?(Integer) }
|
82
|
+
validate('instrumenter') { |val| RedisQueuedLocks::Instrument.valid_interface?(val) }
|
83
|
+
validate('uniq_identifier') { |val| val.is_a?(Proc) }
|
84
|
+
validate('logger') { |val| RedisQueuedLocks::Logging.valid_interface?(val) }
|
85
|
+
validate('log_lock_try') { |val| val == true || val == false }
|
86
|
+
validate('dead_request_ttl') { |val| val.is_a?(Integer) && val > 0 }
|
87
|
+
validate('is_timed_by_default') { |val| val == true || val == false }
|
88
|
+
validate('log_sampler') { |val| RedisQueuedLocks::Logging.valid_sampler?(val) }
|
89
|
+
validate('log_sampling_enabled') { |val| val == true || val == false }
|
90
|
+
validate('log_sampling_percent') { |val| val.is_a?(Integer) && val >= 0 && val <= 100 }
|
91
|
+
validate('instr_sampling_enabled') { |val| val == true || val == false }
|
92
|
+
validate('instr_sampling_percent') { |val| val.is_a?(Integer) && val >= 0 && val <= 100 }
|
93
|
+
validate('instr_sampler') { |val| RedisQueuedLocks::Instrument.valid_sampler?(val) }
|
94
|
+
validate('default_conflict_strategy') do |val|
|
95
|
+
# rubocop:disable Layout/MultilineOperationIndentation
|
96
|
+
val == :work_through ||
|
97
|
+
val == :extendable_work_through ||
|
98
|
+
val == :wait_for_lock ||
|
99
|
+
val == :dead_locking
|
100
|
+
# rubocop:enable Layout/MultilineOperationIndentation
|
101
|
+
end
|
102
|
+
validate('default_access_strategy') do |val|
|
103
|
+
# rubocop:disable Layout/MultilineOperationIndentation
|
104
|
+
val == :queued ||
|
105
|
+
val == :random
|
106
|
+
# rubocop:enable Layout/MultilineOperationIndentation
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [Hash<Symbol,Any>]
|
110
|
+
#
|
111
|
+
# @api private
|
112
|
+
# @since [1.13.0]
|
113
|
+
attr_reader :config_state
|
114
|
+
|
115
|
+
# @return [void]
|
116
|
+
#
|
117
|
+
# @api private
|
118
|
+
# @since [1.13.0]
|
119
|
+
def initialize(&configuration)
|
120
|
+
@config_state = {}
|
121
|
+
config_setters.each_value { |setter| setter.call(@config_state) }
|
122
|
+
configure(&configuration)
|
123
|
+
end
|
124
|
+
|
125
|
+
# @param configuration [Block]
|
126
|
+
# @yield [?]
|
127
|
+
# @yieldparam [?]
|
128
|
+
# @return [void]
|
129
|
+
#
|
130
|
+
# @api private
|
131
|
+
# @since [1.13.0]
|
132
|
+
def configure(&configuration)
|
133
|
+
yield(self) if block_given?
|
134
|
+
end
|
135
|
+
|
136
|
+
# @param config_key [String]
|
137
|
+
# @return [Any]
|
138
|
+
#
|
139
|
+
# @raise [RedisQueuedLocks::ConfigNotFoundError]
|
140
|
+
#
|
141
|
+
# @api public
|
142
|
+
# @since [1.13.0]
|
143
|
+
def [](config_key)
|
144
|
+
prevent_key__non_existent(config_key)
|
145
|
+
config_state[config_key]
|
146
|
+
end
|
147
|
+
|
148
|
+
# @param config_key [String]
|
149
|
+
# @param config_value [Any]
|
150
|
+
# @return [void]
|
151
|
+
#
|
152
|
+
# @raise [RedisQueuedLocks::ConfigNotFoundError]
|
153
|
+
# @raise [RedisQueuedLocks::ConfigValidationError]
|
154
|
+
#
|
155
|
+
# @api public
|
156
|
+
# @since [1.13.0]
|
157
|
+
def []=(config_key, config_value)
|
158
|
+
prevent_key__non_existent(config_key)
|
159
|
+
prevent_key__invalid_type(config_key, config_value)
|
160
|
+
config_state[config_key] = config_value
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns the slice of the config values as a `hash` match the received pattern.
|
164
|
+
# Matched configs will be sliced as a nested config (as a hash object). And config valuess
|
165
|
+
# will be duplicated via `Object#dup`. How it works:
|
166
|
+
# initial config sate: => {
|
167
|
+
# 'swarm.flush_zombies.redis_config.pooled' => true,
|
168
|
+
# 'swarm.flush_zombies.redis_config.sentinel' => true,
|
169
|
+
# 'swarm.aut_swarm' => false,
|
170
|
+
# 'logger' => Logger.new
|
171
|
+
# }
|
172
|
+
# slice with "swarm.flush_zombies.redis_config" pattern: => {
|
173
|
+
# 'pooled' => true,
|
174
|
+
# 'sentinel' => true
|
175
|
+
# }
|
176
|
+
#
|
177
|
+
# @param config_key_pattern [String]
|
178
|
+
# @return [Hash<String,Any>]
|
179
|
+
#
|
180
|
+
# @api public
|
181
|
+
# @since [1.13.0]
|
182
|
+
def slice(config_key_pattern)
|
183
|
+
key_selector = "#{config_key_pattern}."
|
184
|
+
key_splitter = key_selector.size
|
185
|
+
sliced_config = {} #: Hash[String,untyped]
|
186
|
+
|
187
|
+
config_state.each_pair do |config_key, config_value|
|
188
|
+
next unless config_key.start_with?(key_selector)
|
189
|
+
sliced_config_key = config_key[key_splitter..] #: String
|
190
|
+
sliced_config[sliced_config_key] = config_value.dup
|
191
|
+
end
|
192
|
+
|
193
|
+
sliced_config
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
# @param config_key [String]
|
199
|
+
# @return [void]
|
200
|
+
#
|
201
|
+
# @raise [RedisQueuedLocks::ConfigNotFoundError]
|
202
|
+
#
|
203
|
+
# @api private
|
204
|
+
# @since [1.13.0]
|
205
|
+
def prevent_key__non_existent(config_key)
|
206
|
+
unless config_state.key?(config_key)
|
207
|
+
raise(
|
208
|
+
RedisQueuedLocks::ConfigNotFoundError,
|
209
|
+
"Config with '#{config_key}' key does not exist."
|
210
|
+
)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# @param config_key [String]
|
215
|
+
# @param config_value [Any]
|
216
|
+
# @return [void]
|
217
|
+
#
|
218
|
+
# @raise [RedisQueuedLocks::ConfigValidationError]
|
219
|
+
#
|
220
|
+
# @api private
|
221
|
+
# @sicne [1.13.0]
|
222
|
+
def prevent_key__invalid_type(config_key, config_value)
|
223
|
+
unless config_validators[config_key].call(config_value)
|
224
|
+
raise(
|
225
|
+
RedisQueuedLocks::ConfigValidationError,
|
226
|
+
"Trying to assing an invalid value to the '#{config_key}' config key."
|
227
|
+
)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -1,47 +1,63 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# NOTE:
|
4
|
+
# the one-line definition style (like "Error = Class.new(::StandardError)")
|
5
|
+
# is not used cuz that style can not be correctly defined via RBS types: we can not
|
6
|
+
# identify the superclass of our class for a constant;
|
3
7
|
module RedisQueuedLocks
|
4
8
|
# @api public
|
5
9
|
# @since 1.0.0
|
6
|
-
Error
|
10
|
+
class Error < ::StandardError; end
|
7
11
|
|
8
12
|
# @api public
|
9
13
|
# @since 1.0.0
|
10
|
-
ArgumentError
|
14
|
+
class ArgumentError < ::ArgumentError; end
|
11
15
|
|
12
16
|
# @api public
|
13
17
|
# @since 1.0.0
|
14
|
-
LockAlreadyObtainedError
|
18
|
+
class LockAlreadyObtainedError < Error; end
|
15
19
|
|
16
20
|
# @api private
|
17
21
|
# @since 1.11.0
|
18
|
-
|
22
|
+
class LockAcquirementIntermediateTimeoutError < ::Timeout::Error; end
|
19
23
|
|
20
24
|
# @api public
|
21
25
|
# @since 1.0.0
|
22
|
-
|
26
|
+
class LockAcquirementTimeoutError < Error; end
|
23
27
|
|
24
28
|
# @api public
|
25
29
|
# @since 1.0.0
|
26
|
-
|
30
|
+
class LockAcquirementRetryLimitError < Error; end
|
27
31
|
|
28
32
|
# @api private
|
29
33
|
# @since 1.12.0
|
30
|
-
TimedLockIntermediateTimeoutError
|
34
|
+
class TimedLockIntermediateTimeoutError < ::Timeout::Error; end
|
31
35
|
|
32
36
|
# @api pulic
|
33
37
|
# @since 1.0.0
|
34
|
-
TimedLockTimeoutError
|
38
|
+
class TimedLockTimeoutError < Error; end
|
35
39
|
|
36
40
|
# @api public
|
37
41
|
# @since 1.3.0
|
38
|
-
ConflictLockObtainError
|
42
|
+
class ConflictLockObtainError < Error; end
|
39
43
|
|
40
44
|
# @api public
|
41
45
|
# @since 1.9.0
|
42
|
-
SwarmError
|
46
|
+
class SwarmError < Error; end
|
43
47
|
|
44
48
|
# @api public
|
45
49
|
# @since 1.9.0
|
46
|
-
SwarmArgumentError
|
50
|
+
class SwarmArgumentError < ArgumentError; end
|
51
|
+
|
52
|
+
# @api public
|
53
|
+
# @since [1.13.0]
|
54
|
+
class ConfigError < Error; end
|
55
|
+
|
56
|
+
# @api public
|
57
|
+
# @since [1.13.0]
|
58
|
+
class ConfigNotFoundError < ConfigError; end
|
59
|
+
|
60
|
+
# @api pub;ic
|
61
|
+
# @since [1.13.0]
|
62
|
+
class ConfigValidationError < ConfigError; end
|
47
63
|
end
|
@@ -36,6 +36,7 @@ module RedisQueuedLocks::Instrument
|
|
36
36
|
def valid_sampler?(sampler)
|
37
37
|
return false unless sampler.respond_to?(:sampling_happened?)
|
38
38
|
|
39
|
+
# @type var m_obj: Method
|
39
40
|
m_obj = sampler.method(:sampling_happened?)
|
40
41
|
m_sig = m_obj.parameters
|
41
42
|
|
@@ -45,12 +46,17 @@ module RedisQueuedLocks::Instrument
|
|
45
46
|
# => [[:opt, :sampling_percent]]
|
46
47
|
# => [[:req, :sampling_percent], [:block, :block]]
|
47
48
|
# => [[:opt, :sampling_percent], [:block, :block]]
|
48
|
-
|
49
|
+
case m_sig.size
|
50
|
+
when 1
|
51
|
+
# => [[:req, :sampling_percent]]
|
52
|
+
# => [[:opt, :sampling_percent]]
|
49
53
|
prm = m_sig[0][0]
|
50
54
|
prm == :req || prm == :opt
|
51
|
-
|
55
|
+
when 2
|
56
|
+
# => [[:req, :sampling_percent], [:block, :block]]
|
57
|
+
# => [[:opt, :sampling_percent], [:block, :block]]
|
52
58
|
f_prm = m_sig[0][0]
|
53
|
-
s_prm =
|
59
|
+
s_prm = m_sig[1][0]
|
54
60
|
|
55
61
|
# rubocop:disable Layout/MultilineOperationIndentation
|
56
62
|
f_prm == :req && s_prm == :block ||
|
@@ -69,13 +75,14 @@ module RedisQueuedLocks::Instrument
|
|
69
75
|
def valid_interface?(instrumenter)
|
70
76
|
if instrumenter == RedisQueuedLocks::Instrument::ActiveSupport
|
71
77
|
# NOTE: active_support should be required in your app
|
72
|
-
defined?(::ActiveSupport::Notifications)
|
78
|
+
!!defined?(::ActiveSupport::Notifications)
|
73
79
|
elsif instrumenter.respond_to?(:notify)
|
74
80
|
# NOTE: the method signature should be (event, payload). Supported variants:
|
75
81
|
# => [[:req, :event], [:req, :payload]]
|
76
82
|
# => [[:req, :event], [:opt, :payload]]
|
77
83
|
# => [[:opt, :event], [:opt, :payload]]
|
78
84
|
|
85
|
+
# @type var m_obj: Method
|
79
86
|
m_obj = instrumenter.method(:notify)
|
80
87
|
m_sig = m_obj.parameters
|
81
88
|
|
@@ -4,38 +4,75 @@
|
|
4
4
|
# @since 1.0.0
|
5
5
|
module RedisQueuedLocks::Logging::VoidLogger
|
6
6
|
class << self
|
7
|
+
# @param progname [Any]
|
8
|
+
# @parma block [Block]
|
9
|
+
# @return [void]
|
10
|
+
#
|
7
11
|
# @api public
|
8
12
|
# @since 1.0.0
|
9
13
|
def warn(progname = nil, &block); end
|
10
14
|
|
15
|
+
# @param progname [Any]
|
16
|
+
# @parma block [Block]
|
17
|
+
# @return [void]
|
18
|
+
#
|
11
19
|
# @api public
|
12
20
|
# @since 1.0.0
|
13
21
|
def unknown(progname = nil, &block); end
|
14
22
|
|
23
|
+
# @param progname [Any]
|
24
|
+
# @parma block [Block]
|
25
|
+
# @return [void]
|
26
|
+
#
|
15
27
|
# @api public
|
16
28
|
# @since 1.0.0
|
17
29
|
def log(progname = nil, &block); end
|
18
30
|
|
31
|
+
# @param progname [Any]
|
32
|
+
# @parma block [Block]
|
33
|
+
# @return [void]
|
34
|
+
#
|
19
35
|
# @api public
|
20
36
|
# @since 1.0.0
|
21
37
|
def info(progname = nil, &block); end
|
22
38
|
|
39
|
+
# @param progname [Any]
|
40
|
+
# @parma block [Block]
|
41
|
+
# @return [void]
|
42
|
+
#
|
23
43
|
# @api public
|
24
44
|
# @since 1.0.0
|
25
45
|
def error(progname = nil, &block); end
|
26
46
|
|
47
|
+
# @param progname [Any]
|
48
|
+
# @parma block [Block]
|
49
|
+
# @return [void]
|
50
|
+
#
|
27
51
|
# @api public
|
28
52
|
# @since 1.0.0
|
29
53
|
def fatal(progname = nil, &block); end
|
30
54
|
|
55
|
+
# @param progname [Any]
|
56
|
+
# @parma block [Block]
|
57
|
+
# @return [void]
|
58
|
+
#
|
31
59
|
# @api public
|
32
60
|
# @since 1.0.0
|
33
61
|
def debug(progname = nil, &block); end
|
34
62
|
|
63
|
+
# @param severity [Any]
|
64
|
+
# @param message [Any]
|
65
|
+
# @param progname [Any]
|
66
|
+
# @param block [Block]
|
67
|
+
# @return [void]
|
68
|
+
#
|
35
69
|
# @api public
|
36
70
|
# @since 1.0.0
|
37
|
-
def add(
|
71
|
+
def add(severity = nil, message = nil, progname = nil, &block); end
|
38
72
|
|
73
|
+
# @param message [Any]
|
74
|
+
# @retorun [void]
|
75
|
+
#
|
39
76
|
# @api public
|
40
77
|
# @since 1.0.0
|
41
78
|
def <<(message); end
|
@@ -49,7 +49,7 @@ module RedisQueuedLocks::Logging
|
|
49
49
|
prm == :req || prm == :opt
|
50
50
|
elsif m_sig.size == 2
|
51
51
|
f_prm = m_sig[0][0]
|
52
|
-
s_prm =
|
52
|
+
s_prm = m_sig[1][0]
|
53
53
|
|
54
54
|
# rubocop:disable Layout/MultilineOperationIndentation
|
55
55
|
f_prm == :req && s_prm == :block ||
|
@@ -71,9 +71,14 @@ module RedisQueuedLocks::Logging
|
|
71
71
|
|
72
72
|
# NOTE:
|
73
73
|
# - convinient/conventional way to support the popular `semantic_logger` library
|
74
|
-
#
|
75
|
-
#
|
74
|
+
# - see https://logger.rocketjob.io/
|
75
|
+
# - see https://github.com/reidmorrison/semantic_logger
|
76
|
+
# - convinient/conventional way to support the popular `broadcast` RubyOnRails's logger;
|
77
|
+
# - see https://api.rubyonrails.org/classes/ActiveSupport/BroadcastLogger.html
|
78
|
+
# rubocop:disable Layout/LineLength
|
76
79
|
return true if defined?(::SemanticLogger::Logger) && logger.is_a?(::SemanticLogger::Logger)
|
80
|
+
return true if defined?(::ActiveSupport::BroadcastLogger) && logger.is_a?(::ActiveSupport::BroadcastLogger)
|
81
|
+
# rubocop:enable Layout/LineLength
|
77
82
|
|
78
83
|
# NOTE: should provide `#debug` method.
|
79
84
|
return false unless logger.respond_to?(:debug)
|
@@ -87,11 +92,14 @@ module RedisQueuedLocks::Logging
|
|
87
92
|
# => [[:req, :progname]]
|
88
93
|
# => [[:rest], [:block, :block]]
|
89
94
|
# => [[:rest]]
|
95
|
+
# => ((...) method signature): [[:rest, :*], [:keyrest, :**], [:block, :&]]
|
90
96
|
|
97
|
+
# @type var m_obj: Method
|
91
98
|
m_obj = logger.method(:debug)
|
92
99
|
m_sig = m_obj.parameters
|
93
100
|
|
94
|
-
|
101
|
+
case m_sig.size
|
102
|
+
when 2
|
95
103
|
# => [[:opt, :progname], [:block, :block]]
|
96
104
|
# => [[:req, :progname], [:block, :block]]
|
97
105
|
# => [[:rest], [:block, :block]]
|
@@ -103,13 +111,20 @@ module RedisQueuedLocks::Logging
|
|
103
111
|
f_prm == :req && s_prm == :block ||
|
104
112
|
f_prm == :rest && s_prm == :block
|
105
113
|
# rubocop:enable Layout/MultilineOperationIndentation
|
106
|
-
|
114
|
+
when 1
|
107
115
|
# => [[:opt, :progname]]
|
108
116
|
# => [[:req, :progname]]
|
109
117
|
# => [[:rest]]
|
110
118
|
prm = m_sig[0][0]
|
111
119
|
|
112
120
|
prm == :opt || prm == :req || prm == :rest
|
121
|
+
when 3
|
122
|
+
# => [[:rest, :*], [:keyrest, :**], [:block, :&]]
|
123
|
+
f_prm = m_sig[0][0]
|
124
|
+
s_prm = m_sig[1][0]
|
125
|
+
t_prm = m_sig[2][0]
|
126
|
+
|
127
|
+
f_prm == :rest && s_prm == :keyrest && t_prm == :block
|
113
128
|
else
|
114
129
|
false
|
115
130
|
end
|