tutorial

RedwoodJS Application Monitoring with Vigilmon: Health Functions, Heartbeats & Alerts

End-to-end uptime monitoring for your RedwoodJS app — health check functions on the API side, HTTP monitors in Vigilmon, and heartbeat coverage for background jobs.

Your RedwoodJS app went silent at 2 AM. The GraphQL API stopped responding. A Prisma connection pool exhausted itself, and the background job that sends order confirmation emails hasn't run in six hours. Nobody noticed until a customer called support.

RedwoodJS is a full-stack React framework built for the serverless era — Prisma on the database side, GraphQL in the middle, and React cells on the frontend. It's designed to be "The One True Full-Stack App Framework" — but full-stack means both layers can break. Vigilmon gives you the external, independent monitor that watches your RedwoodJS app from outside your own infrastructure.

This tutorial covers monitoring a RedwoodJS app end-to-end with Vigilmon.

What You'll Build

  • A health check function in api/src/functions/
  • A Vigilmon HTTP monitor with assertion
  • A Vigilmon heartbeat monitor for background jobs
  • Alert channels and a status page

Prerequisites

  • A RedwoodJS app (v7.x or later, Node.js 20+)
  • A free account at vigilmon.online

Step 1: Create a Health Check Function

RedwoodJS custom API functions live in api/src/functions/. Each file exports a handler that Redwood maps to a serverless function or an Express route, depending on your deployment target.

Create api/src/functions/health.ts:

// api/src/functions/health.ts
import type { APIGatewayEvent, Context } from "aws-lambda";
import { db } from "src/lib/db";

export const handler = async (_event: APIGatewayEvent, _context: Context) => {
  const checks: Record<string, string> = {};
  let healthy = true;

  // 1. Database probe via Prisma
  try {
    await db.$queryRaw`SELECT 1`;
    checks.database = "ok";
  } catch (e) {
    checks.database = `error: ${(e as Error).message}`;
    healthy = false;
  }

  // 2. Environment sanity check
  const requiredEnvVars = ["DATABASE_URL", "SESSION_SECRET"];
  const missing = requiredEnvVars.filter((v) => !process.env[v]);
  if (missing.length > 0) {
    checks.env = `missing: ${missing.join(", ")}`;
    healthy = false;
  } else {
    checks.env = "ok";
  }

  return {
    statusCode: healthy ? 200 : 503,
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      status: healthy ? "ok" : "degraded",
      checks,
      ts: new Date().toISOString(),
    }),
  };
};

The db.$queryRaw\SELECT 1`` probe exercises the Prisma connection pool with the cheapest possible query. If the database is unreachable, the connection pool is exhausted, or DATABASE_URL is misconfigured, this will fail and return a 503.

Test locally with yarn rw dev running:

curl http://localhost:8911/health

Expected response:

{
  "status": "ok",
  "checks": {
    "database": "ok",
    "env": "ok"
  },
  "ts": "2026-01-15T10:23:00.000Z"
}

Step 2: Deploy and Expose the Endpoint

If you deploy to Netlify Functions or Vercel Serverless, Redwood maps api/src/functions/health.ts to /.netlify/functions/health or /api/health automatically. If you're on a Node.js server via yarn rw serve, the endpoint is at /api/health.

Check your deployment target's URL. For Netlify:

https://your-app.netlify.app/.netlify/functions/health

For Vercel or a custom server:

https://your-app.com/api/health

Step 3: Set Up a Vigilmon HTTP Monitor

  1. Log in to Vigilmon and click New Monitor → HTTP.
  2. Set URL to your health function endpoint.
  3. Set Check interval to 60 seconds.
  4. Set Expected status code to 200.
  5. Under Advanced → JSON body assertion, add:
    • Path: status
    • Expected value: ok
  6. Save the monitor.

Vigilmon polls from multiple external regions. If your Prisma pool drains, a cold start hangs, or your function crashes entirely, you'll get an alert within 60 seconds.


Step 4: Monitor the GraphQL Endpoint

RedwoodJS's GraphQL API is the primary interface for your frontend cells. A broken resolver, a missing directive, or a schema mismatch can cause the entire API layer to return errors while your health function stays green.

Add a second monitor:

  1. Click New Monitor → HTTP in Vigilmon.
  2. Set URL to https://your-app.com/api/graphql.
  3. Set Method to POST.
  4. Under Request Body, add a simple introspection query:
{
  "query": "{ __typename }"
}
  1. Add a header: Content-Type: application/json.
  2. Set Expected status code to 200.
  3. Under Advanced → Keyword check:
    • Keyword present: "__typename"
    • Keyword absent: "errors"
  4. Save.

This verifies that your GraphQL schema is healthy and resolvers aren't crashing on startup.


Step 5: Heartbeat Monitor for Background Jobs

RedwoodJS jobs (scheduled with yarn rw jobs) run as background workers. HTTP monitors can't observe them. Use a heartbeat monitor to detect when jobs stop running.

In your job file:

// api/src/jobs/dailyDigestJob.ts
import { jobs } from "src/lib/jobs";

export const DailyDigestJob = jobs.createJob({
  queue: "default",
  perform: async () => {
    try {
      await sendDailyDigestEmails();

      // Ping Vigilmon heartbeat on success
      const heartbeatUrl = process.env.VIGILMON_HEARTBEAT_URL;
      if (heartbeatUrl) {
        await fetch(heartbeatUrl, { method: "POST" });
      }
    } catch (error) {
      // No ping on failure — Vigilmon alerts on missed ping
      throw error;
    }
  },
});

async function sendDailyDigestEmails() {
  // your email logic
}

Set the environment variable:

VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/<your-id>

In Vigilmon, create a Heartbeat Monitor and set the grace period slightly longer than your job's schedule interval (e.g., 25 hours for a daily job). If the job runner crashes, the queue empties, or the job throws an unhandled error, Vigilmon will alert you.


Step 6: Alert Channels

Go to Notifications → New Channel in Vigilmon and configure:

  • Email — immediate alerts to your on-call inbox
  • Webhook — push to Slack, PagerDuty, or Discord

For Slack, paste your incoming webhook URL. A down alert looks like:

🔴 DOWN: your-app.com/.netlify/functions/health
Status: 503 Service Unavailable
Region: EU-West
2 minutes ago

Step 7: Status Page

Go to Status Pages → New Status Page in Vigilmon. Add all three monitors (health function, GraphQL API, and heartbeat) and publish the page. Embed the status badge in your README:

![App Status](https://vigilmon.online/badge/<monitor-slug>)

What You've Built

| Scenario | How Vigilmon catches it | |---|---| | Prisma connection pool exhausted | Health function returns degraded, alert fires | | Missing environment variable on deploy | Health function returns env: missing, 503 fires | | Broken GraphQL resolver on startup | GraphQL monitor returns error body, keyword alert fires | | Background job runner crashes | Heartbeat misses ping, alert fires | | Entire API function crashes (OOM, syntax error) | HTTP timeout on health endpoint | | Database unreachable (network, credentials) | Prisma SELECT 1 fails inside health function |


RedwoodJS's serverless-first design means your app can disappear silently in ways a traditional server never would. Vigilmon gives you the external view that catches failures no matter which layer breaks.

Start monitoring your RedwoodJS app today — register free at vigilmon.online.

Monitor your app with Vigilmon

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

Start free →