Relay metrics should expose workload and failure trends without creating one time series per event.
Spring relay metrics: measure backlog without event-ID labels
Bound the dimensions
Useful values include due-row count, oldest due-row age, claim conflicts, publish attempts, duplicate consumer results, delivered count and dead-row count. Low-cardinality labels can identify environment, outcome class and a small fixed operation set. An event ID, user ID, tenant ID or raw exception message is too unbounded for a metric tag. Put those values in access-controlled logs or traces with retention limits.
The existing metric-cardinality fixture checks bounded labels on a separate import path. The scheduled poller fixture does not emit relay metrics. This lesson is an instrumentation contract, not evidence of a live dashboard. Spring Boot uses Micrometer for metrics; choose an export backend only after the service exists.
Alert on the work that matters
An empty queue is not automatically healthy: the producer may have stopped writing. Compare accepted commands with outbox inserts and delivered counts. Alert on sustained oldest-due age and dead-row growth, not on every single retry. Record the count of events waiting beyond the service objective.
Computing oldest age may require a database query on each scrape. Bound scrape cost with an index, a cached sampling interval or a background aggregate. Verify the value against actual row state during an outage drill. Batch limits and due times affect the interpretation of that age.
Checked source
// Design sketch; this meter is not installed in the poller fixture.
registry.counter("aitrove.relay.attempts", "outcome", "delivered").increment();Verification boundary
FrameworkBoundaryTest.enumOutcomeBoundsMeterIdentities checks label policy elsewhere in the source kit. The excerpt is shortened or a labelled design sketch; the source kit contains the complete checked fixture.
Costs and limits
No relay meter, exporter, dashboard or alert rule is wired. A counter alone cannot show backlog age or prove delivery, and a database scrape needs a measured query plan.
Common Mistakes
- Do not use event IDs or raw errors as metric tags.
- Do not alert on every retry without a sustained-age signal.
- Do not assume an empty queue proves the producer is running.
Read next
Spring Boot metrics: bound tag values instead of tracking each receipt, Spring outbox polling: cap work per tick and measure backlog age, Spring scheduled retries: leave failed work pending until its due time, Spring outbox retry budget: park a poison event for inspection.
