Skip to content

feat: emit limit:exceeded event when a request is rejected - #21

Merged
thetutlage merged 2 commits into
3.xfrom
feat/limiter-exceeded-event
Oct 15, 2026
Merged

thetutlage merged 2 commits into
3.xfrom
feat/limiter-exceeded-event

Conversation

@thetutlage

Copy link
Copy Markdown
Member

📚 Description

Adds a limit:exceeded event, emitted every time a request is rejected because the key has exhausted its requests.

emitter.on('limit:exceeded', ({ key, response }) => {
  logger.warn({ key, consumed: response.consumed }, 'rate limit exceeded')
})

The event is emitted from every rejection path, exactly once per rejection:

  • Limiter.consume() when the store rejects the request (covers attempt() and MultiLimiter.consume() too)
  • The pre-consume checks in attempt(), penalize(), MultiLimiter.penalize() and HttpLimiter.throttle()

Methods that only update the counters (increment(), set(), block()) do not emit the event. The next rejected request does.

The payload is { key, response }. For limiters created using limiter.define(), the key is prefixed with the limiter name (e.g. login_ip_127.0.0.1), which can be used to identify the limiter.

Wiring

  • The provider passes the app emitter to LimiterManager, which shares it with every Limiter and MultiLimiter it creates.
  • The emitter is optional, so standalone usage is unchanged.
  • The event is registered on EventsList for typed listeners.
  • The event is emitted without awaiting, so listeners never delay the request.

Context

Comes out of the discussion on #19. A global event serves observability for enforced limits as well, and lets the dry run mode proposed in #20 report through the same event instead of the limitExceeded callback.

🤖 Generated with Claude Code

The event is emitted every time a request is rejected because the key
has exhausted its requests, across consume, attempt, penalize, multi
limiters and HTTP throttling. Methods that only update the counters,
like increment or set, do not emit the event.

The provider passes the app emitter to the limiter manager, which shares
it with the limiters it creates. The emitter is optional for standalone
usage.
@thetutlage
thetutlage merged commit 85e6f82 into 3.x Oct 15, 2026
19 checks passed
@MaximeMRF MaximeMRF mentioned this pull request Oct 17, 2026
2 of 3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant