tutorial

How to Monitor Upstash with Vigilmon

Monitor Upstash Redis, Kafka, and QStash with Vigilmon — command latency checks, consumer lag alerts, QStash delivery heartbeats, daily quota guards, and cost anomaly detection for serverless data infrastructure.

Upstash gives you serverless Redis, Kafka, and QStash (HTTP message queue) with per-request pricing and zero idle cost — perfect for edge and serverless environments. But "serverless" doesn't mean "worry-free." A Redis command that starts timing out because a key-space explosion exhausted your daily quota, a Kafka consumer that silently fell behind by thousands of messages, or a QStash delivery that failed and exhausted all retries — these failures won't surface until your app starts behaving strangely. Vigilmon gives you the external monitors, heartbeats, and alerts to catch Upstash issues before your users do.

This tutorial covers monitoring all three Upstash products: Redis, Kafka, and QStash.

What You'll Build

  • A health API route that probes Upstash Redis with a live PING
  • Vigilmon HTTP monitors for your Redis health endpoint
  • A QStash consumer that pings a Vigilmon heartbeat on successful delivery
  • Alerts for Kafka consumer lag and daily quota consumption

Prerequisites

  • An Upstash account with at least one Redis database (Kafka and QStash are optional)
  • A Node.js / Deno / Bun runtime environment (serverless or otherwise)
  • A free account at vigilmon.online

Step 1: Create a Redis Health Check Endpoint

The most reliable way to monitor Upstash Redis is to issue a live PING command from a health endpoint your HTTP monitor can reach.

Install the Upstash Redis SDK

npm install @upstash/redis

app/api/health/route.ts (Next.js App Router)

import { Redis } from "@upstash/redis";

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

export async function GET() {
  const checks: Record<string, string> = {};
  let ok = true;

  // Live Redis PING — measures round-trip to Upstash
  try {
    const start = performance.now();
    const result = await redis.ping();
    const latencyMs = Math.round(performance.now() - start);

    if (result === "PONG") {
      checks.redis = `ok (${latencyMs}ms)`;
    } else {
      checks.redis = `unexpected_response: ${result}`;
      ok = false;
    }
  } catch (err) {
    checks.redis = `error: ${(err as Error).message}`;
    ok = false;
  }

  return Response.json(
    { status: ok ? "ok" : "degraded", checks },
    { status: ok ? 200 : 503 }
  );
}

Plain Node.js / Bun / Deno version

import { Redis } from "@upstash/redis";

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

async function checkRedis(): Promise<{ ok: boolean; latencyMs: number }> {
  const start = performance.now();
  const result = await redis.ping();
  return { ok: result === "PONG", latencyMs: Math.round(performance.now() - start) };
}

Step 2: Add a Vigilmon HTTP Monitor for Redis

  1. Log in to VigilmonAdd Monitor → HTTP.
  2. URL: https://<your-app>/api/health
  3. Check interval: 60 seconds
  4. Response timeout: 5 seconds
  5. JSON assertion: status = ok
  6. Label: "Upstash Redis — production"

Set an alert if the monitor is down for 2 consecutive checks. Upstash Redis REST API is highly available, so repeated failures indicate a real problem (exhausted quota, network issue, or misconfigured credentials).


Step 3: Monitor QStash Delivery with a Heartbeat

QStash delivers HTTP messages to your consumer endpoints with retries. If your consumer endpoint goes down or QStash exhausts all retries on a critical job, you need an alert.

Install QStash SDK

npm install @upstash/qstash

Your QStash consumer endpoint

// app/api/queue/process-order/route.ts
import { verifySignatureAppRouter } from "@upstash/qstash/dist/nextjs";

async function handler(req: Request) {
  const body = await req.json();

  try {
    // Process the queued job
    await processOrder(body.orderId);

    // Ping Vigilmon heartbeat on successful delivery + processing
    await fetch(process.env.VIGILMON_HEARTBEAT_URL!, { method: "POST" });

    return Response.json({ ok: true });
  } catch (err) {
    // Do NOT ping heartbeat — let Vigilmon fire the alert after grace period
    console.error("Order processing failed:", err);
    return Response.json({ error: (err as Error).message }, { status: 500 });
  }
}

export const POST = verifySignatureAppRouter(handler);

Add to your environment:

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

In Vigilmon, create a Heartbeat monitor and set the grace period based on your expected QStash delivery frequency. For a job that fires every hour, use a 90-minute grace period so a single delayed delivery doesn't page you.

What to set alerts for

| QStash failure | Vigilmon response | |---|---| | Consumer endpoint down | HTTP monitor on your consumer URL | | All retries exhausted | Heartbeat misses grace period | | DLQ messages piling up | Custom health endpoint reading DLQ depth |


Step 4: Monitor Kafka Consumer Lag

Upstash Kafka surfaces consumer group lag via the REST API. High lag means your consumers aren't keeping up — messages are queuing up and processing delays will cascade into user-facing problems.

Poll Kafka lag from a health endpoint

// app/api/health/kafka/route.ts

const UPSTASH_KAFKA_REST_URL = process.env.UPSTASH_KAFKA_REST_URL!;
const UPSTASH_KAFKA_REST_USERNAME = process.env.UPSTASH_KAFKA_REST_USERNAME!;
const UPSTASH_KAFKA_REST_PASSWORD = process.env.UPSTASH_KAFKA_REST_PASSWORD!;
const LAG_ALERT_THRESHOLD = 1000; // messages behind

export async function GET() {
  let ok = true;
  const checks: Record<string, unknown> = {};

  try {
    const resp = await fetch(
      `${UPSTASH_KAFKA_REST_URL}/lag/my-consumer-group`,
      {
        headers: {
          Authorization: `Basic ${Buffer.from(
            `${UPSTASH_KAFKA_REST_USERNAME}:${UPSTASH_KAFKA_REST_PASSWORD}`
          ).toString("base64")}`,
        },
        signal: AbortSignal.timeout(5000),
      }
    );

    if (!resp.ok) {
      checks.kafka_lag = `http_error: ${resp.status}`;
      ok = false;
    } else {
      const data = await resp.json();
      const totalLag: number = data.totalLag ?? 0;
      checks.kafka_lag = totalLag;
      if (totalLag > LAG_ALERT_THRESHOLD) {
        checks.kafka_lag_status = `high (${totalLag} messages behind)`;
        ok = false;
      } else {
        checks.kafka_lag_status = "ok";
      }
    }
  } catch (err) {
    checks.kafka_lag = `error: ${(err as Error).message}`;
    ok = false;
  }

  return Response.json(
    { status: ok ? "ok" : "degraded", checks },
    { status: ok ? 200 : 503 }
  );
}

Add a Vigilmon HTTP monitor pointing at /api/health/kafka with a JSON assertion status = ok.


Step 5: Guard Daily Request Quotas

Upstash free-tier Redis and Kafka databases have a daily request limit. When your app exceeds it, Upstash starts rejecting commands — your Redis calls will throw errors that look like network failures.

Add a quota check to your health endpoint using the Upstash REST API's database info endpoint:

// Extend your existing health route
try {
  const resp = await fetch(
    `${process.env.UPSTASH_REDIS_REST_URL}/info`,
    {
      headers: { Authorization: `Bearer ${process.env.UPSTASH_REDIS_REST_TOKEN}` },
      signal: AbortSignal.timeout(3000),
    }
  );
  const info = await resp.json();
  const dailyUsed: number = info.daily_requests_used ?? 0;
  const dailyLimit: number = info.daily_request_limit ?? Infinity;
  const usagePct = Math.round((dailyUsed / dailyLimit) * 100);
  checks.quota = `${usagePct}% (${dailyUsed}/${dailyLimit})`;
  if (usagePct >= 90) {
    checks.quota_status = "critical";
    ok = false;
  } else if (usagePct >= 75) {
    checks.quota_status = "warning";
    // Return 200 but include warning in payload
  }
} catch (err) {
  checks.quota = `error: ${(err as Error).message}`;
}

Set a Vigilmon JSON assertion to fail when quota_status equals critical so you get an alert before you hit the wall.


Step 6: Embed the Status Page

Vigilmon generates a public status page for all your monitors. Go to Status Pages → Create, add your Upstash monitors, then embed the badge:

[![Uptime](https://vigilmon.online/badge/<monitor-id>.svg)](https://vigilmon.online/status/<status-page-slug>)

Key Metrics to Watch

| Metric | Monitor type | Vigilmon feature | |---|---|---| | Redis availability (PING) | HTTP monitor on health route | 60 s HTTP check with JSON assertion | | Redis command latency | Health route returns latency | JSON assertion on latency field | | QStash delivery success | Heartbeat from consumer | Heartbeat monitor with grace period | | Kafka consumer lag | HTTP monitor on lag route | JSON assertion on lag threshold | | Daily request quota | Health route polls REST info | JSON assertion on quota_status | | Cost anomaly | External metric endpoint | Vigilmon HTTP check + alert |


Alerting Recommendations

  • Slack webhook — post to #data-infrastructure when Redis or Kafka checks degrade
  • Email — on-call address for quota exhaustion alerts (billing impact)
  • PagerDuty — for production Redis outages affecting live transactions

Set re-notification every 5 minutes while a monitor is down. Upstash quota exhaustion escalates fast once you cross the threshold — catch it early.


Upstash manages the infrastructure. Vigilmon manages the question "is my data layer reachable and healthy right now?" — from the outside, the way your app's users experience it.

Start monitoring your Upstash infrastructure 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 →