DEV Community

Vigilmon
Vigilmon

Posted on

How to Monitor Your Java/Spring Boot App Uptime (Free, Multi-Region)

Your Spring Boot app is running in production — but is it actually up? The framework gives you Spring Actuator out of the box, but no one is watching the /actuator/health endpoint unless you set up external monitoring. One silent 503 at 3 AM can cost you users and revenue before anyone wakes up.

By the end of this guide you'll have external uptime monitoring, multi-region checks, heartbeat monitoring for your scheduled tasks, and a public status page — all running on the free tier.


Why Spring Boot apps still go dark

Spring Boot apps have two failure modes that fly under the radar:

Endpoint failures — your API starts returning 500s, the connection pool is exhausted, or a bad deploy breaks a route. Your health endpoint might still return UP while individual APIs are broken.

Silent @Scheduled task failures — a @Scheduled method throws an unchecked exception. Spring catches it, logs a line, and keeps going. Your nightly data sync just stopped running. Nobody knows.

Both are solvable with one external monitoring tool actively checking from outside your infrastructure.


Step 1: Add Spring Actuator and expose the health endpoint

Add the Actuator dependency to your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Or with Gradle in build.gradle:

implementation 'org.springframework.boot:spring-boot-starter-actuator'
Enter fullscreen mode Exit fullscreen mode

By default, only /actuator/health is exposed over HTTP. That's exactly what you need. The endpoint returns:

{
  "status": "UP"
}
Enter fullscreen mode Exit fullscreen mode

To expose component-level details (database, disk space, custom checks), add this to application.properties:

management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=health
Enter fullscreen mode Exit fullscreen mode

Now the response shows which components are healthy:

{
  "status": "UP",
  "components": {
    "db": {
      "status": "UP",
      "details": {
        "database": "PostgreSQL",
        "validationQuery": "isValid()"
      }
    },
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 499963174912,
        "free": 423123456789,
        "threshold": 10485760
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

When the database is down, db.status becomes DOWN and the top-level status becomes DOWN with HTTP 503 — exactly the signal your monitoring tool needs.


Step 2: Write a custom health indicator

For dependencies that Actuator doesn't cover automatically, implement HealthIndicator:

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class ExternalApiHealthIndicator implements HealthIndicator {

    private final ExternalApiClient apiClient;

    public ExternalApiHealthIndicator(ExternalApiClient apiClient) {
        this.apiClient = apiClient;
    }

    @Override
    public Health health() {
        try {
            boolean reachable = apiClient.ping();
            if (reachable) {
                return Health.up().withDetail("external-api", "reachable").build();
            }
            return Health.down().withDetail("external-api", "unreachable").build();
        } catch (Exception e) {
            return Health.down(e).build();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

This component is automatically picked up and included in the /actuator/health response.


Step 3: Set up external monitoring with Vigilmon

With /actuator/health live, point Vigilmon at it:

  1. Sign up at vigilmon.online — free tier, no credit card
  2. Click New Monitor → HTTP
  3. Enter https://yourdomain.com/actuator/health
  4. Set check interval (5 minutes on free tier)
  5. Save

Vigilmon probes from multiple regions. If it gets a non-2xx response or a timeout, it opens an incident and alerts you immediately — before your users notice.

Add multiple monitors per service:

Endpoint What it catches
/actuator/health Database down, disk full, custom checks
/api/v1/ping API layer breakage
/ Frontend serving broken

Step 4: Heartbeat monitoring for @Scheduled tasks

HTTP uptime checks don't detect silent @Scheduled failures. Heartbeat monitoring does.

The pattern: your scheduled method pings a unique URL at the end of each successful run. If Vigilmon stops receiving the ping within the expected window, it fires an alert.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ReportScheduler {

    @Value("${heartbeat.report.url:}")
    private String reportHeartbeatUrl;

    private final RestTemplate restTemplate = new RestTemplate();

    @Scheduled(cron = "0 0 2 * * *") // daily at 2 AM
    public void generateDailyReport() {
        try {
            // your report logic here
            processReport();

            // Only ping on success
            if (!reportHeartbeatUrl.isEmpty()) {
                restTemplate.getForObject(reportHeartbeatUrl, String.class);
            }
        } catch (Exception e) {
            // log the error — don't ping the heartbeat
            throw e;
        }
    }

    private void processReport() {
        // actual report generation
    }
}
Enter fullscreen mode Exit fullscreen mode

In Vigilmon:

  1. Click New Monitor → Heartbeat
  2. Set the expected interval (e.g. 25 hours for a daily job)
  3. Copy the unique ping URL
  4. Add it to your application.properties:
heartbeat.report.url=https://vigilmon.online/api/heartbeat/your-unique-token
Enter fullscreen mode Exit fullscreen mode

Now if your scheduled job throws an exception, the heartbeat is never pinged, and Vigilmon alerts you within one missed interval.


Step 5: Webhook alerts and badge embed

Slack/Discord alerts:

  1. In Vigilmon go to Notifications → New Channel
  2. Choose Slack or Discord, paste your webhook URL
  3. Enable it on your monitors

You'll get instant alerts when a monitor goes down and a recovery notification when it comes back up.

Add an uptime badge to your README:

In Vigilmon, open any monitor and copy the badge embed code. It looks like this:

[![Uptime](https://vigilmon.online/badge/your-monitor-id.svg)](https://vigilmon.online?utm_source=devto&utm_medium=article&utm_campaign=java-tutorial)
Enter fullscreen mode Exit fullscreen mode

Drop it at the top of your README.md or your internal docs. The badge stays green as long as your monitors are up and flips red during an incident.


What you've built

What How
External health checks /actuator/health + Vigilmon HTTP monitor
Custom dependency checks HealthIndicator implementation
Scheduled task monitoring Heartbeat ping inside @Scheduled methods
Instant alerts Slack/Discord notifications
README status badge Vigilmon badge embed

The whole setup runs on the free tier and takes under 30 minutes. You'll catch the next silent failure before your users do.


Get started free at vigilmon.online — monitors running in under a minute, no credit card required.

Top comments (0)