Subversion Repositories SmartDukaan

Rev

Rev 34583 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
34554 tejus.loha 1
package com.smartdukaan.cron.monitored;
2
 
34583 tejus.loha 3
import java.lang.reflect.Method;
34554 tejus.loha 4
import java.util.Date;
5
import java.util.Map;
6
import java.util.concurrent.ConcurrentHashMap;
34567 tejus.loha 7
import java.util.concurrent.ConcurrentMap;
8
import java.util.concurrent.atomic.AtomicInteger;
34554 tejus.loha 9
 
10
import io.micrometer.core.instrument.Counter;
34567 tejus.loha 11
import io.micrometer.core.instrument.Gauge;
12
import io.micrometer.core.instrument.Timer;
34554 tejus.loha 13
import org.aspectj.lang.ProceedingJoinPoint;
14
import org.aspectj.lang.annotation.Around;
15
import org.aspectj.lang.annotation.Aspect;
34583 tejus.loha 16
import org.aspectj.lang.reflect.MethodSignature;
34554 tejus.loha 17
import org.springframework.beans.factory.annotation.Autowired;
18
import org.springframework.stereotype.Component;
19
 
20
import io.micrometer.core.instrument.MeterRegistry;
21
import org.slf4j.Logger;
22
import org.slf4j.LoggerFactory;
23
 
24
@Aspect
25
@Component
26
public class CronJobMonitorAspect {
27
 
28
    private static final Logger log = LoggerFactory.getLogger(CronJobMonitorAspect.class);
29
 
30
    @Autowired
31
    private MeterRegistry meterRegistry;
32
 
37484 amit 33
    private static final int NOT_RUN_YET = -1;
34
 
34567 tejus.loha 35
    private final ConcurrentMap<String, AtomicInteger> lastStatus = new ConcurrentHashMap<>();
34554 tejus.loha 36
 
37
    @Around("@annotation(org.springframework.scheduling.annotation.Scheduled)")
38
    public Object monitorCronJob(ProceedingJoinPoint joinPoint) throws Throwable {
34567 tejus.loha 39
        String methodName = joinPoint.getSignature().getName();
37484 amit 40
        // -1, not 0. The gauge is registered when a job STARTS, and 0 means
41
        // "failed" -- so a long-running job reported failure for the whole of its
42
        // first execution after every restart, which is indistinguishable from a
43
        // real failure. That is what put ten jobs on the board as FAILED after the
44
        // 2026-08-31 restart. CronJobFailing matches == 0, so -1 is excluded until
45
        // the job has actually finished once.
34567 tejus.loha 46
        lastStatus.computeIfAbsent(methodName, m -> {
37484 amit 47
            AtomicInteger gauge = new AtomicInteger(NOT_RUN_YET);
34567 tejus.loha 48
            Gauge.builder("cron_job_last_status", gauge, AtomicInteger::get)
37484 amit 49
                    .description("1=success, 0=failure, -1=not finished a run yet")
34567 tejus.loha 50
                    .tag("method", m)
51
                    .register(meterRegistry);
52
            return gauge;
53
        });
54
 
55
        boolean success = false;
56
 
57
        // Start a timer sample
58
        Timer.Sample sample = Timer.start(meterRegistry);
34554 tejus.loha 59
        try {
60
            Object result = joinPoint.proceed();
34567 tejus.loha 61
            success = true;
62
            // Record a success count
34583 tejus.loha 63
            meterRegistry.counter(
64
                    "cron_job_count_total", "method", methodName, "status", "success").increment();
34554 tejus.loha 65
            return result;
34567 tejus.loha 66
        } catch (Throwable t) {
67
            // Record a failure count with exception type
68
            meterRegistry.counter(
34583 tejus.loha 69
                    "cron_job_count_total", "method", methodName, "status", "failure").increment();
34567 tejus.loha 70
            throw t;
71
        } finally {
72
            sample.stop(Timer.builder("cron_job_duration_seconds")
73
                    .tag("method", methodName)
74
                    .register(meterRegistry));
75
            lastStatus.get(methodName).set(success ? 1 : 0);
34554 tejus.loha 76
 
77
        }
78
    }
79
 
80
}