TradeOrderRecoveryObservability.java
package com.ecommerce.trade.infrastructure.observability;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Component;
import java.time.Clock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@Component
public class TradeOrderRecoveryObservability {
public static final String TASK_NAME = "order_recovery";
private final Clock clock;
private final AtomicInteger running = new AtomicInteger();
private final AtomicLong lastCompletionMillis;
private final Counter succeeded;
private final Counter failed;
private final Timer duration;
public TradeOrderRecoveryObservability(MeterRegistry meterRegistry, Clock clock) {
this.clock = clock;
this.lastCompletionMillis = new AtomicLong(clock.millis());
this.succeeded = executions(meterRegistry, "success");
this.failed = executions(meterRegistry, "failure");
this.duration = Timer.builder("ecommerce.task.scheduler.duration")
.description("Duration of a governed scheduled task execution")
.tag("service", "trade-service")
.tag("task", TASK_NAME)
.register(meterRegistry);
Gauge.builder("ecommerce.task.scheduler.running", running, AtomicInteger::get)
.description("Whether a governed scheduled task is currently running")
.tag("service", "trade-service")
.tag("task", TASK_NAME)
.register(meterRegistry);
Gauge.builder("ecommerce.task.scheduler.completion.age", this, TradeOrderRecoveryObservability::completionAgeSeconds)
.description("Seconds since a governed scheduled task last completed")
.baseUnit("seconds")
.tag("service", "trade-service")
.tag("task", TASK_NAME)
.register(meterRegistry);
}
public void observe(Runnable action) {
Timer.Sample sample = Timer.start();
running.set(1);
try {
action.run();
succeeded.increment();
} catch (RuntimeException exception) {
failed.increment();
throw exception;
} finally {
lastCompletionMillis.set(clock.millis());
running.set(0);
sample.stop(duration);
}
}
private double completionAgeSeconds() {
return Math.max(0L, clock.millis() - lastCompletionMillis.get()) / 1000.0d;
}
private Counter executions(MeterRegistry meterRegistry, String result) {
return Counter.builder("ecommerce.task.scheduler.executions")
.description("Governed scheduled task execution outcomes")
.tag("service", "trade-service")
.tag("task", TASK_NAME)
.tag("result", result)
.register(meterRegistry);
}
}