Build1 distinct publisher2 min readUpdated
A limit of 100 per minute becomes 200 the moment a second worker keeps its own counter, and whatever the storage adapter does on a timeout decides who gets in when the backend dies.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Scale to six workers holding independent counters and the number printed in your API documentation has quietly become 600 [2]. That is worth writing down before any adapter gets picked: the advertised limit is a function of deployment topology, and an autoscaler edits it without touching your code. The source's own example is the small version of this, two workers at 60 apiece against a 100 per minute limit, 20 percent over with both workers behaving correctly [2][1].
A shared store fixes the arithmetic and buys a failure domain in exchange [5]. Redis keeps the counter near the operation and does the increment-and-compare atomically in a Lua script [5][12]. PostgreSQL does the same work with UPSERTs inside transactions, and is the reasonable choice when the database is already part of the service and the limiter is not on its hottest path [6][7][12]. The trap the author names for that path is row contention on hot keys [6]. A hot key in a rate limiter is the identifier sending the most requests, which is the identifier the limiter exists to slow down, so the contention arrives in step with the abuse.
Then the store times out. A retry can ride out a brief network fault while adding latency to a request a user is waiting on. A circuit breaker stops the hammering and still owes an answer for every request that arrives while it is open. An allow-through fallback keeps the endpoint serving and removes the protection the limiter was installed to provide [8]. None of those three is a storage detail, though the storage layer is where they usually end up living. If the adapter ships an undocumented default, the adapter has authored the policy for every route that imports it, and a login endpoint does not deserve the same answer as a public read [9].
A local denial cache is worth having and worth being honest about: it keeps already-blocked traffic off the backend, and it does nothing to make two workers agree about a request neither has seen [10]. Pressure relief, not consensus.
The useful test is cheap. Run two workers against one key, kill the backend, and record what the endpoint actually returns [14]. That exercises the deployment rather than the algorithm, which is why the three questions the source puts first, worker count, timeout behaviour, per-check latency budget, narrow the choice faster than any feature comparison [13]. Keeping the contract small, check one identifier, check a batch, clear state, is what lets the adapter change later [11]. It does not choose for you.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
A rate limiter can start as a Map and a counter, which is enough for a single process; the design changes when two workers must enforce the same limit.
With a limit of 100 requests per minute for one user, Worker A sees 60 requests and Worker B sees 60 more; each worker stays below the limit while the user has sent 120. The application enforced two local limits, not one shared limit.
The storage backend affects the result the limiter returns, the latency of the check, and how the service behaves when the backend fails.
An in-memory limiter adds no network dependency, keeps the check inside the process, and is cheap to run and easy to test; restarting the process destroys the state, and a second worker starts with its own view of traffic.
Redis is presented as a strong default for a shared limiter on a busy request path: it keeps state close to the operation and supports atomic updates through Lua scripts, at the cost of a network call, connection management, and a new failure domain.
PostgreSQL suits an application that already depends on it; UPSERTs and transactions can coordinate updates, but hot keys can create row contention, and a database call on every request deserves a clear latency budget.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Internally coherent reasoning, single self-published source, nothing measured
The mechanism claims are self-evident and internally consistent: the two-worker arithmetic holds without external data, and the trade-off lists for memory, Redis and PostgreSQL are standard and clearly stated. But the entire cluster is one self-published dev.to post by the tool's own author, with no benchmark, latency figure, contention measurement, code audit or second source. Latency budgets are named as a decision constraint yet never quantified, and the described RateLock implementations are asserted rather than demonstrated.
No adoption evidence in cluster
The supplied material contains no release, deployment, benchmark, pricing, licensing or usage disclosure for RateLock or for any of the storage patterns described - only a link to the project's documentation site. There is no basis to estimate adoption without inventing facts.
Sober framing, mildly overstated on the author's own project
The prose is deliberately hedged - defaults are called starting defaults, trade-offs are named on both sides, and the reader is told to write constraints down before benchmarking - so the general guidance is close to aligned with its evidence. The gap comes from the promotional turn: RateLock is presented as the resolution of the problem the article frames, with adapter-level implementation claims and no benchmark, maturity, or usage evidence to support the implied readiness. The headline framing that a limit of 100 becomes 200 is arithmetic that the source's own example supports, so it is not itself inflated.
Maintainer post that ends in a link to their own project
The author writes in the first person about a problem space and then presents RateLock, their own project, as embodying the recommended contract and adapters, closing with a documentation link. The framing choices - a small storage-agnostic contract with local, Redis and PostgreSQL adapters - map exactly onto what the project ships, so the analysis and the promotion are inseparable. There is no disclosed sponsorship, pricing or commercial arrangement in the cluster, so the incentive is reputational and project-promotional rather than demonstrably financial.
High confidence in the mechanism, low confidence beyond it
Confidence is high that the described multi-worker overcounting problem and the enumerated backend trade-offs are real and correctly stated, since they follow from the source's own arithmetic and are widely understood engineering facts. Confidence is low on everything requiring corroboration: RateLock's behaviour and maturity, any latency or contention numbers, and whether the recommended defaults generalise. With one self-interested source and zero adoption evidence, the assessment cannot be raised further.
build
Three services you can delete: queue, cache and search in one Postgres1 distinct publisher
build
Four control planes, one Postgres: a team's case against polyglot persistence1 distinct publisher
build
A RAG stack lived seven hours before a hosted embedding endpoint returned 4041 distinct publisher
build
One Mutable vat_id Column Is An Audit Failure With A Delay Fuse1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 23, 2026