tutorial

How to Monitor Apache Isis / Causeway Apps (Free, Multi-Region)

Apache Isis (now Apache Causeway) generates full web UIs from your domain model — but when the app server goes down or a background command fails, nobody knows. Set up external uptime monitoring and heartbeat checks in under 30 minutes, free.

How to Monitor Apache Isis / Causeway Apps (Free, Multi-Region)

Apache Isis — rebranded as Apache Causeway — lets you build domain-driven apps where the UI, REST API, and persistence are all derived from annotated Java domain objects. It's powerful, but when the JDO/JPA persistence layer fails or a background CommandExecutorService silently drops work, there's no built-in external watcher.

By the end of this guide you'll have external uptime monitoring, heartbeat checks for your background command processor, and instant alerts — all running on the free tier.


Why Causeway applications go dark silently

Causeway apps have two failure modes that slip through the cracks:

Application server failures — the embedded Tomcat or Jetty instance crashes, a JDO DataNucleus connection pool exhausts, or a bad migration leaves the database schema inconsistent. The app may start but return 500s on every page. No external alert fires unless something is watching from outside.

Silent background command failures — Causeway's CommandExecutorService runs actions asynchronously. If the persistence layer throws during command execution, the command is retried or dropped depending on configuration. Your domain event handlers stop running, and the app looks fine from the outside.

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


Step 1: Expose a health endpoint

Causeway builds on Spring Boot, so Spring Actuator works out of the box. Add it to your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Expose the health endpoint in application.properties:

management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=health

The default /actuator/health response already reflects your DataSource connectivity:

{
  "status": "UP",
  "components": {
    "db": { "status": "UP" },
    "diskSpace": { "status": "UP" }
  }
}

When the JDO/JPA connection pool is exhausted, db.status becomes DOWN and the HTTP response becomes 503 — exactly what your monitoring tool needs.


Step 2: Add a custom Causeway health indicator

For deeper checks — like verifying the CommandServiceJpa table is reachable or that your fixture data loaded — implement a Spring Boot HealthIndicator that uses the Causeway IsisSystemEnvironment:

import org.apache.causeway.applib.services.iactnlayer.InteractionService;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

import javax.inject.Inject;

@Component
public class CausewayHealthIndicator implements HealthIndicator {

    @Inject
    private InteractionService interactionService;

    @Override
    public Health health() {
        try {
            // Verify the interaction factory can open a new interaction
            interactionService.openInteraction();
            interactionService.closeInteractionLayers();
            return Health.up()
                    .withDetail("causeway-interaction", "ok")
                    .build();
        } catch (Exception e) {
            return Health.down(e)
                    .withDetail("causeway-interaction", "failed")
                    .build();
        }
    }
}

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


Step 3: Set up external monitoring with Vigilmon

With the health endpoint 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 simultaneously. A non-2xx response or timeout opens an incident and alerts you before your users notice.

Recommended monitors for a Causeway app:

| Endpoint | What it catches | |---|---| | /actuator/health | DB down, JDO pool exhausted, custom checks | | /causeway/restful/ | REST API layer broken | | /wicket/ | Wicket UI serving broken |


Step 4: Heartbeat monitoring for background command processing

HTTP checks don't catch silent background command failures. Heartbeat monitoring does.

The pattern: your command processor pings a unique URL after each successful batch. If Vigilmon stops receiving the ping within the expected window, it fires an alert.

import org.apache.causeway.applib.services.command.CommandExecutorService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

@Service
public class BackgroundCommandProcessor {

    private static final String HEARTBEAT_URL =
            System.getenv("HEARTBEAT_CMD_PROCESSOR_URL");

    private final CommandExecutorService commandExecutorService;

    public BackgroundCommandProcessor(CommandExecutorService commandExecutorService) {
        this.commandExecutorService = commandExecutorService;
    }

    @Scheduled(fixedDelay = 60_000) // every minute
    public void processBackgroundCommands() {
        try {
            // Execute pending background commands
            commandExecutorService.executeBackgroundCommands();

            // Only ping on success
            pingHeartbeat();
        } catch (Exception e) {
            // Log — but do NOT ping the heartbeat URL
            System.err.println("Background command processing failed: " + e.getMessage());
            throw e;
        }
    }

    private void pingHeartbeat() {
        if (HEARTBEAT_URL == null || HEARTBEAT_URL.isBlank()) return;
        try {
            HttpClient.newHttpClient().send(
                    HttpRequest.newBuilder(URI.create(HEARTBEAT_URL)).GET().build(),
                    HttpResponse.BodyHandlers.discarding()
            );
        } catch (Exception ignored) {}
    }
}

In Vigilmon:

  1. Click New Monitor → Heartbeat
  2. Set the expected interval (e.g. 5 minutes for a per-minute processor)
  3. Copy the unique ping URL
  4. Set HEARTBEAT_CMD_PROCESSOR_URL in your environment

If the processor fails before pingHeartbeat() is called, the ping is never sent 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 an instant alert when a monitor goes down and a recovery notification when it comes back up.

Add an uptime badge to your README:

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

What you've built

| What | How | |---|---| | External health checks | /actuator/health + Vigilmon HTTP monitor | | Causeway-specific checks | Custom HealthIndicator via interaction service | | Background command monitoring | Heartbeat ping after each batch | | Instant alerts | Slack/Discord notifications | | README status badge | Vigilmon badge embed |

The entire setup runs on the free tier in under 30 minutes. The next time a background command processor silently stops, you'll know about it before your domain events pile up.


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

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →