DEV Community

Vigilmon
Vigilmon

Posted on

How to Monitor AWS RDS and Aurora with Vigilmon

How to Monitor AWS RDS and Aurora with Vigilmon

AWS RDS and Aurora provide managed database infrastructure, but "managed" doesn't mean "always up." Databases go into maintenance windows, connection pools exhaust, and replica lag grows. This guide shows how to build application-level database monitoring that surfaces problems before users hit errors.

What to Monitor

RDS/Aurora health has two layers:

  1. AWS-level: instance status, CPU, storage-visible in CloudWatch
  2. Application-level: can your app actually query the database?-visible via your health endpoint

Vigilmon monitors layer 2. CloudWatch handles layer 1. You need both.

Adding a Database Health Endpoint

Node.js with pg (PostgreSQL/Aurora Postgres)

` ypescript
import express from "express";
import { Pool } from "pg";

const pool = new Pool({
host: process.env.RDS_HOSTNAME,
port: parseInt(process.env.RDS_PORT || "5432"),
database: process.env.RDS_DB_NAME,
user: process.env.RDS_USERNAME,
password: process.env.RDS_PASSWORD,
ssl: { rejectUnauthorized: false }, // Required for RDS SSL
connectionTimeoutMillis: 5000,
idleTimeoutMillis: 30000,
max: 20,
});

const app = express();

app.get("/health", async (req, res) => {
const start = Date.now();

try {
const result = await pool.query("SELECT 1 as ok, NOW() as ts");
const latency = Date.now() - start;

res.json({
  status: "ok",
  database: {
    connected: true,
    latencyMs: latency,
    timestamp: result.rows[0].ts,
  },
});
Enter fullscreen mode Exit fullscreen mode

} catch (error) {
console.error("DB health check failed:", error);
res.status(503).json({
status: "error",
database: {
connected: false,
error: error instanceof Error ? error.message : "Unknown error",
},
});
}
});

app.listen(3000);
`

Python with SQLAlchemy (Aurora MySQL/Postgres)

`python
from flask import Flask, jsonify
from sqlalchemy import create_engine, text
from sqlalchemy.exc import OperationalError
import os
import time

app = Flask(name)

engine = create_engine(
f"postgresql://{os.environ['DB_USER']}:{os.environ['DB_PASSWORD']}"
f"@{os.environ['DB_HOST']}:{os.environ.get('DB_PORT', '5432')}/{os.environ['DB_NAME']}",
pool_pre_ping=True, # Test connection before use
pool_size=5,
max_overflow=10,
connect_args={
"connect_timeout": 5,
"sslmode": "require" # Required for RDS
}
)

@app.route("/health")
def health():
start = time.time()
try:
with engine.connect() as conn:
result = conn.execute(text("SELECT 1"))
latency_ms = int((time.time() - start) * 1000)

    return jsonify({
        "status": "ok",
        "database": {
            "connected": True,
            "latencyMs": latency_ms
        }
    }), 200
except OperationalError as e:
    return jsonify({
        "status": "error",
        "database": {
            "connected": False,
            "error": str(e)
        }
    }), 503
Enter fullscreen mode Exit fullscreen mode

if name == "main":
app.run(port=5000)
`

Go with database/sql

`go
package main

import (
"database/sql"
"encoding/json"
"fmt"
"net/http"
"os"
"time"

_ "github.com/lib/pq"
Enter fullscreen mode Exit fullscreen mode

)

var db *sql.DB

func healthHandler(w http.ResponseWriter, r *http.Request) {
start := time.Now()

err := db.PingContext(r.Context())
latency := time.Since(start).Milliseconds()

w.Header().Set("Content-Type", "application/json")

if err != nil {
    w.WriteHeader(http.StatusServiceUnavailable)
    json.NewEncoder(w).Encode(map[string]interface{}{
        "status": "error",
        "database": map[string]interface{}{
            "connected": false,
            "error":     err.Error(),
        },
    })
    return
}

json.NewEncoder(w).Encode(map[string]interface{}{
    "status": "ok",
    "database": map[string]interface{}{
        "connected":  true,
        "latencyMs": latency,
    },
})
Enter fullscreen mode Exit fullscreen mode

}

func main() {
connStr := fmt.Sprintf(
"host=%s port=%s user=%s password=%s dbname=%s sslmode=require",
os.Getenv("DB_HOST"),
os.Getenv("DB_PORT"),
os.Getenv("DB_USER"),
os.Getenv("DB_PASSWORD"),
os.Getenv("DB_NAME"),
)

var err error
db, err = sql.Open("postgres", connStr)
if err != nil {
    panic(err)
}
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)

http.HandleFunc("/health", healthHandler)
http.ListenAndServe(":8080", nil)
Enter fullscreen mode Exit fullscreen mode

}
`

Aurora-Specific: Read Replica Monitoring

Aurora provides a reader endpoint for read replicas. Monitor it separately:

` ypescript
// Monitor writer endpoint
const writerPool = new Pool({ host: process.env.AURORA_WRITER_ENDPOINT, ... });

// Monitor reader endpoint

const readerPool = new Pool({ host: process.env.AURORA_READER_ENDPOINT, ... });

app.get("/health", async (req, res) => {
const [writerOk, readerOk] = await Promise.allSettled([
writerPool.query("SELECT 1"),
readerPool.query("SELECT 1"),
]);

const status = writerOk.status === "fulfilled" ? "ok" : "error";

res.status(status === "ok" ? 200 : 503).json({
status,
writer: writerOk.status === "fulfilled" ? "ok" : "error",
reader: readerOk.status === "fulfilled" ? "ok" : "degraded",
});
});
`

In Vigilmon, add two monitors:

Handling RDS Maintenance Windows

During RDS maintenance, connections drop briefly. Your health endpoint may return 503. Configure Vigilmon to require 2 consecutive failures before alerting to avoid false alarms:

In Vigilmon ? Monitor settings ? Failure threshold: 2

This means one failed check won't page you, but two in a row will.

Setting Up Vigilmon

  1. Go to vigilmon.online
  2. Add monitors for:
    • Your app's /health endpoint (HTTP check)
    • Your RDS domain (TCP check on port 5432/3306)
    • Your SSL certificate

TCP Monitor for RDS Direct

If you want to monitor the RDS endpoint directly:

  • Type: TCP
  • Host: your-instance.xxxx.us-east-1.rds.amazonaws.com
  • Port: 5432 (PostgreSQL) or 3306 (MySQL)
  • Interval: 5 minutes

Note: Ensure your Vigilmon probe IPs are allowed in your RDS security group, or use application-level health endpoints instead.

Recommended Alert Setup

Event Alert
Health endpoint 503 Slack + PagerDuty (immediate)
Response time >2s Slack (warning)
SSL expiry <30d Email
2+ consecutive failures PagerDuty (wake-up)

Summary

  • Add a /health endpoint that actively queries RDS/Aurora
  • Return 503 when the database is unreachable
  • Monitor writer and reader endpoints separately for Aurora
  • Set failure threshold to 2 to avoid maintenance window false alarms
  • Use Vigilmon for external checks + CloudWatch for AWS-level metrics

Set up RDS monitoring at vigilmon.online - free plan includes 3 monitors.

Top comments (0)