+14
−0
Loading
Adds a SADD+SCARD-backed counter alongside the existing INCR-backed one,
exposed as Limiter#check_unique(identifier, member:) and #peek_unique.
The limit constrains the number of distinct members observed within the
rule's period rather than the number of calls — the labkit-side
equivalent of ApplicationRateLimiter::IncrementPerActionedResource.
Lays the foundation for the cohort 4 rollout
(unique_project_downloads_for_{application,namespace}, EE GitAbuse).
The follow-up consumer-side MR will:
- add `mode: :unique` and `accepts_override: true` to those two
SupportedRateLimits entries (both call sites always pass
threshold:/interval: overrides; without accepting them the labkit
path never runs),
- plumb `resource.id` through LabkitAdapter#run_unique! as `member:`,
- add `rate_limiter_use_labkit_cohort_4{,_enforce}` feature flags.
Design notes:
- Separate public API (check_unique / peek_unique) rather than a `mode:`
kwarg on #check. SET-mode and INCR-mode have mutually-exclusive
per-call shapes (cost vs member) and operate on incompatible Redis
data types — two narrow APIs read more clearly than one polymorphic
one and avoid WRONGTYPE foot-guns.
- EXPIRE-on-first-write is gated on `added && scard == 1`, matching the
legacy IncrementPerActionedResource semantic (a re-SADD of an
existing member should not reset the window).
- Member is to_s-coerced and SHA-256-encoded above CHAR_VALUE_MAX_LENGTH,
identical to characteristic-value handling, so callers can pass
arbitrary subjects without worrying about Redis key bloat.
- Pipelined (not Lua), mirroring the current INCR path on master.
If !291's atomic Lua INCR lands, a follow-up can convert this path
to a parallel atomic script (SADD + SCARD + EXPIRE in one round-trip).
Co-Authored-By:
Claude Opus 4.7 (1M context) <noreply@anthropic.com>