Event contract
Fields the query expects
| Field | Type | Why it exists |
|---|---|---|
| timestamp_utc | Timestamp | Attempt completion time in UTC. |
| route_template | Utf8 | Stable route template. |
| request_id | Utf8 | Identifier shared by the original attempt and retries. |
| attempt_number | Int64 | One-based attempt sequence. |
| status_code | Int64 | HTTP status returned for the attempt. |
| retry_after_ms | Int64 | Applied retry delay in milliseconds. |
| environment | Utf8 | Deployment environment. |
Copy the query
WITH request_outcomes AS (
SELECT
route_template,
request_id,
COUNT(*) AS attempts,
MAX(CASE WHEN status_code = 429 THEN 1 ELSE 0 END) AS was_rate_limited,
MAX(CASE WHEN status_code BETWEEN 200 AND 299 THEN 1 ELSE 0 END) AS succeeded
FROM api_attempt_events
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
AND environment = 'production'
GROUP BY route_template, request_id
)
SELECT
route_template,
COUNT(*) AS requests,
SUM(was_rate_limited) AS rate_limited_requests,
SUM(CASE
WHEN was_rate_limited = 1 AND succeeded = 1 THEN 1
ELSE 0
END) AS recovered_requests,
100.0 * SUM(CASE
WHEN was_rate_limited = 1 AND succeeded = 1 THEN 1
ELSE 0
END) / NULLIF(SUM(was_rate_limited), 0) AS recovery_rate_pct
FROM request_outcomes
GROUP BY route_template
ORDER BY rate_limited_requests DESC, route_template;This read-only query is planned and executed against an empty typed table with Apache DataFusion 45.2.0. The deterministic sample output is synthetic and reviewed separately; validate field types, thresholds, and business definitions against your own data. Read the testing methodology.
Query result
Rate-limited request recovery
Search recovers two of three rate-limited requests; export does not recover in the observed window.
| route_template | requests | rate_limited_requests | recovered_requests | recovery_rate_pct |
|---|---|---|---|---|
| /api/search | 4 | 3 | 2 | 66.67 |
| /api/export | 2 | 1 | 0 | 0 |
Synthetic example output. Run the query against your own event schema and thresholds before using it for operational decisions.
Reproduce the example
Download the public fixture
The JSON bundle includes the typed event contract, reproducible input rows, exact SQL, expected output, review notes, and engine version. The CSV contains the displayed result.
How the SQL works
- 1The first CTE creates one record per logical request, preventing retries from inflating request volume.
- 2A request counts as recovered only when it contains both a 429 attempt and a successful attempt.
- 3Keeping rate-limited request count beside the percentage makes low-volume results visible.
Edge cases to decide
- Use an idempotency or logical request identifier that survives retries.
- Bound the retry sequence so a request that completes after the reporting window is not permanently labeled failed.
- Record client cancellations separately from retry exhaustion.
Recommended dashboard
- Bars: recovery_rate_pct by route
- Trend: rate_limited_requests and recovered_requests
- Table: exhausted requests with attempt count and retry delay
Alert guidance
Alert when rate-limited volume is material and recovery stays below the route's reviewed target for several buckets.
Read alert setupPut the recipe to work
Related instrumentation and guides
Continue the analysis
Calculate API Error Rate by Route
Use SQL to rank API routes by 5xx error rate while protecting the result from low-volume noise.
Open recipeCalculate p50, p95, and p99 API Latency
Compare median and tail latency by endpoint with DataFusion-compatible percentile SQL.
Open recipeCalculate API Error-Budget Burn Rate
Turn hourly request failures into an SLO burn-rate series that shows how quickly the allowed error budget is being consumed.
Open recipeRun it on real events
Create a table, adapt the fields, and save the result
Start free, send structured events, and use the query result as a chart, shared dashboard widget, or alert input.