Class: Labkit::RateLimit::Matcher
- Inherits:
-
Object
- Object
- Labkit::RateLimit::Matcher
- Defined in:
- lib/labkit/rate_limit/matcher.rb
Overview
Matcher is the internal representation of a single key/value predicate in a Rule#match hash. Rule.new normalizes every match value through Matcher.build; the Evaluator calls Matcher#match? per identifier value.
Accepted input shapes (everything else raises ArgumentError):
- any plain value (String, Symbol, Integer, ...) -> :eq matcher
- a Regexp instance -> :re matcher (Ruby convenience)
- { eq: <value> } -> :eq matcher (canonical, YAML-compatible)
- { re: <String|Regexp> } -> :re matcher (canonical, YAML-compatible)
Hash-key naming follows the metrics-catalog selector pattern. Glob, prefix, and other matcher kinds are intentionally out of scope here; see gitlab-com/gl-infra/production-engineering#28853 for that follow-up.
An :re matcher coerces the identifier value via #to_s before applying the regex, so callers can match non-String identifier values such as Integer status codes (e.g. { re: "^5" } against status: 503).
Constant Summary collapse
- KNOWN_HASH_KEYS =
%i[eq re].freeze
- MAX_REGEX_SOURCE_LENGTH =
200- ERROR_INSPECT_LIMIT =
80- MATCH_TIMEOUT_SECONDS =
Wall-clock budget for a single #match? call. Without it a match is bounded only by whatever global the host sets (40s in GitLab Rails, unbounded elsewhere), and a timeout reaches Evaluator's fail-open rescue, so the request goes unlimited.
5ms is ~119x the slowest real match measured against GitLab's RackAttack path patterns on inputs up to 16KB (worst: 0.0419ms, none timed out). Re-measure if a rule ever needs nested quantifiers or backreferences, which are what make backtracking exponential.
0.005
Class Method Summary collapse
Instance Method Summary collapse
Class Method Details
.build(input) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/labkit/rate_limit/matcher.rb', line 38 def self.build(input) case input when Regexp new(type: :re, value: with_match_timeout(input)) when Hash from_hash(input) when Array raise ArgumentError, "rate-limit match value must be a single-key Hash like {re: \"...\"} or {eq: ...}, got #{truncate_for_error(input)}" else new(type: :eq, value: input) end end |
Instance Method Details
#match?(identifier_value) ⇒ Boolean
122 123 124 125 126 127 128 129 130 131 |
# File 'lib/labkit/rate_limit/matcher.rb', line 122 def match?(identifier_value) case type when :eq value == identifier_value when :re value.match?(identifier_value.to_s) else raise ArgumentError, "unknown matcher type: #{type.inspect}" end end |