Class: Wurk::Limiter::Base
- Inherits:
-
Object
- Object
- Wurk::Limiter::Base
show all
- Defined in:
- lib/wurk/limiter/base.rb
Overview
Shared base for every limiter type. Holds the public introspection
contract documented in §1.5 — name / type / options / size / status /
reset / delete plus the within_limit(...) { ... } block. Subclasses
override the acquire path and the per-type metric/size methods.
status is uniform across types (#16): { used:, limit:, reset_at:, available? }. Subclasses supply the three values via build_status;
Concurrent additionally merges its metric counters.
Instance Attribute Summary collapse
Instance Method Summary
collapse
Constructor Details
#initialize(name, register: true, **options) ⇒ Base
register: defaults true so constructing a limiter publishes its
metadata + lmtr-list membership. The dashboard reconstructs limiters
purely to read status on a GET, so it passes register: false to
keep introspection side-effect-free.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
# File 'lib/wurk/limiter/base.rb', line 24
def initialize(name, register: true, **options)
unless name.is_a?(String) && NAME_PATTERN.match?(name)
raise ArgumentError, "limiter name must match #{NAME_PATTERN.inspect} (got #{name.inspect})"
end
ttl = options[:ttl] || DEFAULT_TTL
raise ArgumentError, 'ttl must be >= 86_400' if ttl < 86_400
@name = name.dup.freeze
@options = options
register! if register
end
|
Instance Attribute Details
#name ⇒ Object
Returns the value of attribute name.
18
19
20
|
# File 'lib/wurk/limiter/base.rb', line 18
def name
@name
end
|
#options ⇒ Object
Returns the value of attribute options.
18
19
20
|
# File 'lib/wurk/limiter/base.rb', line 18
def options
@options
end
|
Instance Method Details
#build_status(used:, limit:, reset_at:) ⇒ Object
Assemble the uniform status hash. available? is derived: an
unlimited (nil) limit is always available; otherwise headroom remains
while used < limit. reset_at is an epoch-seconds Float (or nil
when the type has no clock-driven reset).
84
85
86
87
|
# File 'lib/wurk/limiter/base.rb', line 84
def build_status(used:, limit:, reset_at:)
{ used: used, limit: limit, reset_at: reset_at,
available?: limit.nil? || used < limit }
end
|
#delete ⇒ Object
63
64
65
66
67
68
|
# File 'lib/wurk/limiter/base.rb', line 63
def delete
Wurk::Limiter.redis do |c|
(state_keys + [meta_key]).each { |k| c.call('DEL', k) }
c.call('SREM', LIST_KEY, @name)
end
end
|
#fingerprint ⇒ Object
Stable fingerprint for the limiter — Sidekiq 8.0+ switched from
SHA1 → SHA256 (~10% larger encoding). Web UI groups limiters by
this so that interpolated names (stripe-#{user_id}) get a single
row per shape.
74
75
76
|
# File 'lib/wurk/limiter/base.rb', line 74
def fingerprint
@fingerprint ||= Digest::SHA256.hexdigest("#{type}|#{@name}|#{JSON.dump(serializable_options)}")
end
|
#lua(name, keys:, argv:) ⇒ Object
89
90
91
|
# File 'lib/wurk/limiter/base.rb', line 89
def meta_key
"lmtr:#{@name}"
end
|
#random_id ⇒ Object
Stable random slot id (Concurrent) / nonce (Window). 16 hex chars
8 bytes — wide enough to avoid collision under any realistic
burst and short enough to keep ZSET memory bounded.
127
128
129
|
# File 'lib/wurk/limiter/base.rb', line 127
def random_id
SecureRandom.hex(8)
end
|
#register! ⇒ Object
107
108
109
110
111
112
113
114
115
116
117
118
|
# File 'lib/wurk/limiter/base.rb', line 107
def register!
Wurk::Limiter.redis do |c|
c.call('SADD', LIST_KEY, @name)
c.call(
'HSET', meta_key,
'type', type.to_s,
'options', JSON.dump(serializable_options),
'fingerprint', fingerprint
)
c.call('EXPIRE', meta_key, @options[:ttl])
end
end
|
#reset ⇒ Object
57
58
59
60
61
|
# File 'lib/wurk/limiter/base.rb', line 57
def reset
Wurk::Limiter.redis do |c|
state_keys.each { |k| c.call('DEL', k) }
end
end
|
#serializable_options ⇒ Object
97
98
99
100
101
102
103
104
105
|
# File 'lib/wurk/limiter/base.rb', line 97
def serializable_options
@options.transform_values do |v|
case v
when Proc then '<proc>'
when Symbol, Numeric, String, true, false, nil then v
else v.to_s
end
end
end
|
#size ⇒ Object
47
48
49
|
# File 'lib/wurk/limiter/base.rb', line 47
def size
0
end
|
#state_keys ⇒ Object
93
94
95
|
# File 'lib/wurk/limiter/base.rb', line 93
def state_keys
[]
end
|
#status ⇒ Object
Uniform across types (#16). Subclasses override to fill in real
numbers; the default reports an idle, unlimited shape.
53
54
55
|
# File 'lib/wurk/limiter/base.rb', line 53
def status
build_status(used: 0, limit: nil, reset_at: nil)
end
|
#ttl ⇒ Object
120
121
122
|
# File 'lib/wurk/limiter/base.rb', line 120
def ttl
@options[:ttl]
end
|
#type ⇒ Object
39
40
41
|
# File 'lib/wurk/limiter/base.rb', line 39
def type
raise NotImplementedError
end
|
#within_limit ⇒ Object
43
44
45
|
# File 'lib/wurk/limiter/base.rb', line 43
def within_limit(**, &)
raise NotImplementedError
end
|