StreamMetricsProvider is the SPI through which FlowWarden Stream Core emits metrics events — stream lifecycle, event flow, errors, checkpoints, DLQ writes, leadership changes. Implementations are fire-and-forget: they must never throw, never block the calling thread.
The default implementation is a no-op. The FlowWarden Reporter is the canonical implementation — it aggregates the callbacks and forwards them either to the FlowWarden Console (heartbeat-style protobuf) or to a Micrometer registry (Prometheus). Custom implementations are wired by calling FlowWardenMetrics.setProvider(...) at startup.
How wiring works
UnlikeLockService / CheckpointStore / DlqStore, this SPI is not resolved as a Spring bean. The framework reads the active provider through a static registry:
StreamMetricsProvider.noOp(). If no provider registers, every callback is silently dropped — Stream Core has no overhead and no behavioural dependency on metrics being collected.
Callback contract
The default methods on the interface are{} empty so an implementation only overrides the callbacks it cares about — adding a new optional callback in a future version of FlowWarden does not break existing providers.
Lifecycle callbacks
onStreamStopped is emitted in three situations, captured by StopReason:
StopReason | When | cause |
|---|---|---|
GRACEFUL | Explicit stopStream(), JVM shutdown, leadership loss. | null |
CRASHED | Uncaught Throwable killed the imperative listener container, or the reactive pipeline terminated on an unexpected onError / onComplete. | The escaping throwable (or null if it could not be captured) |
CRASHED signal exists so monitoring can distinguish a silently dead stream from an intentional stop — without it, dashboards would report RUNNING indefinitely. Always handle CRASHED explicitly in custom providers; treating it identically to GRACEFUL masks real outages.
Event flow callbacks
onEventReceivedis called when an event arrives from MongoDB, before any handler runs.onEventProcessedis called after the handler returns —success=falseif it threw andsuccess=trueif it returned cleanly (after all configured retries succeeded).onEventErroris called when a handler throws.willRetry=truemeans the framework will retry (under the configuredRetryPolicy);willRetry=falsemeans the budget is exhausted and the event will move to DLQ or be dropped.
Buffer & backpressure callbacks
onBufferStatus is invoked when the internal event buffer size changes meaningfully (the framework batches these — not one call per event). onBackpressure fires when an action from BackpressureAction is triggered (e.g. drop-oldest, throttle).
Checkpoint callbacks
onCheckpointis emitted only on confirmed write success from theCheckpointStore. If the store throws, this is not invoked —onCheckpointFailedis, with the thrown cause. Stream-core does not stop the stream on a checkpoint write failure; it logs the failure, emits the signal, and keeps processing.- The three resume callbacks signal level-2 and level-3 events in the resume cascade — see @Checkpoint resume cascade for the cascade rules. They are graceful-degradation signals (the stream continues; the operator may want to investigate why a level-2 or level-3 fallback happened).
onCheckpointLagis called periodically with the current lag betweenlastSeenTokenandlastProcessedToken— useful for monitoring streams whose handlers fall behind.
DLQ callbacks
onEventSentToDlqis emitted only on confirmed write success from theDlqStore.onEventDlqFailedfires when the store throws. A DLQ write failure is operationally critical: the event has neither been processed by the handler nor archived for later replay. Stream-core logs and emits the signal; the auto post-retry path then resumes the stream, while manualctx.sendToDlq(...)paths re-throw to the user handler. Wire alerts on this signal.
Infrastructure & leadership callbacks
onOplogStatsreports the MongoDB oplog window size.statusis"OK","UNAVAILABLE"(collection inaccessible — e.g. Atlas shared tier), or"ERROR". A shrinking window matters for resume safety — a short window relative to your downtime meansonHistoryLostis closer than you think.onLeadershipChangefires onSINGLE_LEADERstreams when the local instance’s role changes.roleis"LEADER","STANDBY", or"NOT_APPLICABLE"(forALL_INSTANCESstreams).
Provided implementations
| Implementation | Module | What it does |
|---|---|---|
NoOpStreamMetricsProvider | flowwarden-stream-core | Default. Silently discards all callbacks. Active until something calls setProvider. |
| FlowWarden Reporter | flowwarden-reporter | Aggregates callbacks per stream; ships them to the FlowWarden Console (protobuf heartbeat) and/or to a Micrometer registry. The canonical reference implementation. |
No contract test ships in
flowwarden-stream-core-testkit for this SPI — the surface is large and the contract is “don’t throw, don’t block” rather than algorithmic. The Reporter is validated through its own integration tests against the protobuf wire format and the Micrometer registry.Providing a custom implementation
Implement the interface, override only the callbacks you care about, and register at startup:See Also
FlowWarden Reporter
The canonical implementation: Console + Prometheus modes.
@Checkpoint resume cascade
Context for the three
onResumeFallback* callbacks.CheckpointStore SPI
The store whose write success / failure feeds
onCheckpoint*.DlqStore SPI
The store whose write success / failure feeds
onEventSentToDlq / onEventDlqFailed.