AL+

Language: RO (română) EN (English)

Email us: paul@alplustech.com

Decide whose quota a Rails rate limit spends

Separate dynamic Rails quotas from request identity and shared counters to assess tenant fairness, deployment scope and the limits of IP-based enforcement.

Citiți articolul în română

A quota derived from a customer's plan is useful only when requests spend the right customer's allowance. Dynamic values solve the amount and duration of a rate limit. Identity and storage decide who shares that limit and whether different application processes enforce the same policy. A product can get the first part right while treating its tenants unfairly.

Rails' 14 November 2025 digest described a change allowing to: and within: to accept controller method names and callables, alongside static values. That makes a policy dependent on request context easier to express. The maintainer digest describes framework development, however, rather than announcing that every installed stable release supports the change.

The underlying pull request #56128 was opened on 11 November and merged into main on 12 November 2025. Those dates establish the change's development chronology. They cannot identify the first stable release containing it. Before adopting dynamic syntax, check the exact installed version and its implementation. The argument here does not require a speculative code sample.

An allowance needs an owner

Consider a hypothetical reporting service with several staff accounts per customer organisation. Its commercial agreement allows the organisation a shared quantity of report requests. Looking up the organisation's plan can determine the quota value. It does not automatically make the organisation the identity used by the counter.

If the counter groups requests by staff account, adding staff creates more independent allowances. If it groups by IP address, unrelated organisations behind a shared network may compete for the same allowance. A mobile user changing networks may move between counters. These examples illustrate policy mismatches; they are not observations from a deployed customer system.

Choose the owner in the same language as the agreement. An organisation allowance should refer to a trusted organisation identity. A user allowance should have an explicit rule for users who belong to several organisations. Authentication and tenant selection must already have resolved that context when the policy evaluates it. A client-supplied tenant identifier is not sufficient proof of membership.

The Rails 8.1.0 API reference documents an IP-based default identity, a configurable by: identity, controller scoping and a cache-backed store. It is a versioned stable reference for those established mechanisms. It should not be read as evidence that the later dynamic change was already present there.

Separate counter identity from enforcement scope

Even the correct identity can leave a quota fragmented. Suppose two controllers both start the same expensive reporting work. If the policy is meant to cover both, their counters must deliberately share the intended scope. Conversely, a shared counter for unrelated actions can make a cheap request consume an allowance intended for a costly operation.

The meaning of a request also deserves a decision. Does a rejected attempt spend the allowance? Does polling for completion count like starting a report? These are product questions before they are limiter settings. A clear policy lets a developer inspect each entry point and explain which budget it consumes. A dynamic plan lookup cannot supply that explanation on its own.

Changing a plan raises a further question about an active counting window. Decide what customers should expect when an allowance increases or decreases. Avoid promising a billing-grade usage ledger merely because a request limiter reads a subscription tier. Enforcement counters and commercial usage records can have different lifetimes and recovery requirements.

Shared traffic requires shared state

The Rails reference says rate limiting uses an ActiveSupport cache store, with a configurable store for the limiter. That choice affects the boundary over which counts are visible. The versioned documentation is the basis for that storage claim, not proof that any particular deployment has configured it correctly.

With independent process-local stores, requests handled by different processes can encounter different counts. Scaling the application can then change the effective allowance without changing the written policy. A shared store is a starting point when the intended budget spans those processes. Its counter behaviour and expiry still need to match the selected adapter and deployment.

Store failure needs a deliberate response too. Continuing requests and refusing requests have different consequences for customers and capacity. Specify what the application should do if counts cannot be read or updated, and make that behaviour visible to the operator. There is no universally correct failure policy for both a public information page and an expensive authenticated export.

Static IP limits can be the right choice

The strongest counterargument is a small public endpoint with no customer-specific entitlement. A static limit by IP can be a proportionate way to constrain repeated requests. Introducing account-aware dynamic quotas would add identity and subscription dependencies without improving the endpoint's actual policy.

Shared networks remain a limitation, but limitations can be acceptable when their effects are understood. A public form may need a coarse abuse boundary rather than perfect allocation between organisations. That should be described honestly. It should not become an unstated promise that all customers receive a precisely fair share of backend work.

Even authenticated products may need separate controls for anonymous entry points. A tenant budget cannot protect requests that arrive before a tenant is known. Likewise, limiting request counts does not make two differently expensive reports equal in resource consumption. Work queues and concurrency policies address another part of the capacity problem.

For a dynamic quota, write down the allowance owner, the actions sharing its counter and the processes sharing its state. Then confirm that the installed Rails version supports the intended evaluation mechanism. A custom software assessment can resolve those boundaries before a plan-based number is mistaken for a complete fairness policy.