Annotation Interface Costly
What this bounds, and what it does not
The budget is a count of requests in flight, not a rate and not a per-client quota. A route carrying@Costly("vectors") runs at most as many times concurrently as the vectors
pool has permits, whoever is asking; the surplus is answered 503 rather than queued indefinitely.
The distinction matters because the traffic this exists for does not come from one client. A scraper spread over thousands of addresses trips no per-IP rate limit — every address is well behaved on its own — while the aggregate still puts every connection in the pool on a matrix fetch. Counting concurrency instead of requests-per-client is indifferent to how the load is distributed, which is the property that makes it worth having alongside whatever the front Apache is doing.
It is not a defence against a determined attacker: a full pool is a 503, and a 503 is still a response. What it buys is that the database and heap see a bounded number of expensive queries regardless of the arrival pattern, so the site degrades to "some requests are refused" instead of "nothing responds".
- See Also:
-
Required Element Summary
Required Elements -
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptionintHow long a request waits for a permit before being answered 503, in seconds.
-
Element Details
-
value
String valueName of the pool this route draws permits from.Routes naming the same pool share one budget, so group routes that contend for the same resource. Must be a key of
CostlyEndpointBudget#POOLS; an unknown name fails fast at startup rather than silently going unbounded. -
queueSeconds
int queueSecondsHow long a request waits for a permit before being answered 503, in seconds.A short wait absorbs a burst that clears quickly without making the caller retry. A long one just moves the queue from the client into the servlet container's thread pool, which is the thing the budget exists to protect, so keep this small.
- Default:
2
-