Class: Wurk::Limiter::Base

Inherits:
Object
  • Object
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.

Direct Known Subclasses

Bucket, Concurrent, Leaky, Points, Window

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.

Raises:

  • (ArgumentError)


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
  # Spec §1.2: ttl floor of 24h. Anything tighter risks losing the
  # metadata hash mid-job and orphaning slots that read it.
  raise ArgumentError, 'ttl must be >= 86_400' if ttl < 86_400

  @name = name.dup.freeze
  @options = options
  register! if register
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



18
19
20
# File 'lib/wurk/limiter/base.rb', line 18

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



18
19
20
# File 'lib/wurk/limiter/base.rb', line 18

def options
  @options
end

Instance Method Details

#deleteObject



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

#fingerprintObject

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

#resetObject



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

#sizeObject



47
48
49
# File 'lib/wurk/limiter/base.rb', line 47

def size
  0
end

#statusObject

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

#typeObject

Raises:

  • (NotImplementedError)


39
40
41
# File 'lib/wurk/limiter/base.rb', line 39

def type
  raise NotImplementedError
end

#within_limitObject

Raises:

  • (NotImplementedError)


43
44
45
# File 'lib/wurk/limiter/base.rb', line 43

def within_limit(**, &)
  raise NotImplementedError
end