Monitor Java scheduled jobs: Spring @Scheduled and Spring Batch with LastPing
For @Scheduled methods: wrap the body in try/catch, GET
the ping URL on success, POST the exception message to
/fail and re-throw on failure. For Spring Batch: add a
JobExecutionListener that checks BatchStatus
and pings accordingly. Absence detection covers JVM OOM kills and the
pod that never started. No extra dependencies — java.net.http
works from Java 11. Free, no monitor cap.
The snippets
Create a monitor in the console, set the schedule to match your cron expression plus a grace window, copy the ping URL, and add it to your Spring bean.
Spring @Scheduled with RestTemplate
Inject the ping URL from application.properties.
Re-throwing after the /fail ping lets Spring's
scheduler exception handler and log the failure:
Spring @Scheduled with Java 11 HttpClient (no extra deps)
Spring Batch — JobExecutionListener
For Spring Batch jobs, implement JobExecutionListener
and wire it as a bean. afterJob fires after every run,
and BatchStatus tells you whether to ping success or
failure. Register it in your @Bean Job builder:
Why re-throw matters in @Scheduled
Re-throwing keeps Spring's
TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLER from silently
swallowing the exception. With a re-throw the scheduler logs the
stack trace and, if you've configured
@EnableAsync or a custom
AsyncUncaughtExceptionHandler, your alerting pipeline
still fires. The LastPing ping adds fast alerting;
it doesn't replace Spring's error propagation. See also the
cron job guide and the
LastPing MCP server for AI-agent integration.
What this catches
The catch reports what it can; the silence reports the rest.
- A thrown exception — the
/failping opens an incident immediately with the exception message stored on the ping event. - A Spring Batch FAILED status — the
JobExecutionListenercollects all failure exceptions and POSTs them to/fail. - JVM OOM kill — the process sends no ping; the grace window raises the alert without any working code on the failure side.
- The job never ran — pod crash-loop, missing cron entry, dead host. Absence → incident.
- Recovery — the next successful run closes the incident and sends a recovery notice automatically.
Questions people ask
Front-loaded answers — the most important fact first.
-
Do I need a dependency like OkHttp or Apache HttpClient?
No.
java.net.http.HttpClient(Java 11+) handles GET and POST without additional dependencies.RestTemplateorWebClientfrom Spring are convenient but not required. -
What if Spring's scheduler swallows the exception?
Spring's default
TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLERlogs the exception but suppresses it so the scheduler keeps running. The/failping still fires because it is sent inside the catch block before re-throwing. Configure a customTaskSchedulererror handler if you need further propagation. -
How do I monitor a Quartz job in Java?
Implement a
JobListenerand add ping calls injobWasExecuted— checkjobExecutionExceptionfor null to distinguish success from failure. The ping URL is the same; only the hook mechanism differs. -
Is this free?
Yes. LastPing is free and fully hosted with no monitor cap and no paid tier. See how it compares to Healthchecks.io and Cronitor.
The JVM logs the exception. LastPing wakes you up.
One listener now beats debugging a missed nightly batch later. First alert wired up in about a minute — and LastPing monitors itself the same way.