Wasm-bindgen is the foundational tool for bridging Rust WebAssembly modules and JavaScript — it generates the glue code that lets your WASM functions call JavaScript APIs and vice versa. It powers everything from performance-critical data processing libraries to full-featured browser apps. But WASM modules running in the browser still depend on backend APIs, data feeds, and infrastructure — all of which can fail silently. Vigilmon provides continuous HTTP monitoring, heartbeat checks, and instant alerts so you know the moment something breaks — before your users do.
What You'll Build
- A
/healthendpoint for your wasm-bindgen backend API server - Vigilmon HTTP monitors for your app and API
- A heartbeat monitor for background processing jobs
- Alert channels (email and Slack)
- A status badge fetched from JavaScript and rendered alongside your WASM output
Prerequisites
- A Rust/wasm-bindgen project with a backend API (Axum, Actix-web, or similar)
- A free Vigilmon account
Step 1: Add a Health Endpoint
Your WASM module runs in the browser, but your backend API server needs an HTTP health endpoint that Vigilmon can poll at regular intervals. Here's an example with Axum:
// backend/src/main.rs
use axum::{
http::StatusCode,
response::Json,
routing::get,
Router,
};
use serde_json::{json, Value};
use tower_http::services::ServeDir;
async fn health_handler() -> (StatusCode, Json<Value>) {
let mut checks = serde_json::Map::new();
let mut degraded = false;
// Database connectivity check
match check_database().await {
Ok(_) => { checks.insert("database".into(), json!("ok")); }
Err(e) => {
checks.insert("database".into(), json!(format!("error: {}", e)));
degraded = true;
}
}
// External API dependency check
match check_external_api().await {
Ok(_) => { checks.insert("external_api".into(), json!("ok")); }
Err(e) => {
checks.insert("external_api".into(), json!(format!("error: {}", e)));
degraded = true;
}
}
let status_code = if degraded { StatusCode::SERVICE_UNAVAILABLE } else { StatusCode::OK };
(status_code, Json(json!({
"status": if degraded { "degraded" } else { "ok" },
"checks": checks,
})))
}
async fn check_database() -> Result<(), String> {
// pool.acquire().await.map_err(|e| e.to_string())?;
Ok(())
}
async fn check_external_api() -> Result<(), String> {
// reqwest::get("https://api.example.com/ping").await.map_err(|e| e.to_string())?;
Ok(())
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/health", get(health_handler))
// Serve WASM module and JS glue from wasm-pack output
.nest_service("/", ServeDir::new("pkg"));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Test it locally:
curl http://localhost:3000/health | jq .
# {"status":"ok","checks":{"database":"ok","external_api":"ok"}}
Step 2: Configure Vigilmon HTTP Monitors
Log in to Vigilmon → Monitors → New Monitor:
Monitor 1: WASM App (Frontend)
| Field | Value |
|---|---|
| URL | https://yourapp.com/ |
| Method | GET |
| Expected status | 200 |
| Expected body | A stable string from your index.html |
| Check interval | 1 minute |
Monitor 2: Health API
| Field | Value |
|---|---|
| URL | https://yourapp.com/health |
| Method | GET |
| Expected status | 200 |
| Expected body | "status":"ok" |
| Check interval | 1 minute |
Monitoring the WASM bundle endpoint separately from the API catches a CDN failure that serves stale or broken .wasm files while the API remains healthy.
Step 3: Heartbeat for Background Processing Jobs
wasm-bindgen modules often process data generated by backend workers — number-crunching pipelines, ML inference servers, or data transformation jobs. A Vigilmon heartbeat monitor detects when these workers stop silently:
// backend/src/worker.rs
use std::time::Duration;
use tokio::time;
const VIGILMON_HEARTBEAT_URL: &str = env!("VIGILMON_HEARTBEAT_URL");
#[tokio::main]
async fn main() {
let mut interval = time::interval(Duration::from_secs(300)); // 5 minutes
loop {
interval.tick().await;
match run_processing_job().await {
Ok(_) => {
// Only ping after successful processing
if let Err(e) = ping_heartbeat().await {
eprintln!("[worker] Heartbeat ping failed: {}", e);
}
}
Err(e) => {
eprintln!("[worker] Processing failed: {} — skipping heartbeat ping", e);
// No ping → Vigilmon alerts when the heartbeat window expires
}
}
}
}
async fn run_processing_job() -> Result<(), Box<dyn std::error::Error>> {
// CPU-intensive data transformation that feeds your WASM module
Ok(())
}
async fn ping_heartbeat() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
client
.get(VIGILMON_HEARTBEAT_URL)
.timeout(Duration::from_secs(5))
.send()
.await?;
Ok(())
}
Set up the heartbeat in Vigilmon:
- Monitors → New Heartbeat Monitor
- Set Expected interval to 10 minutes (2× the worker interval)
- Add the ping URL to your build environment:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx
Step 4: Embed an Uptime Badge via JavaScript
With wasm-bindgen, your WASM module interacts with the browser DOM through JavaScript. The cleanest pattern is to render the Vigilmon badge from the JavaScript glue layer rather than inside the Rust WASM code:
// index.js (JS entry point that loads your WASM module)
import init, { run_app } from "./pkg/your_app.js";
const BADGE_URL = "https://vigilmon.online/api/badge/your-monitor-id.svg";
const STATUS_URL = "https://vigilmon.online/status/your-monitor-slug";
async function bootstrap() {
// Initialize the WASM module
await init();
// Run your wasm-bindgen exported function
run_app();
// Add Vigilmon uptime badge after WASM initializes
appendUptimeBadge();
}
function appendUptimeBadge() {
const footer = document.createElement("footer");
footer.className = "footer";
const link = document.createElement("a");
link.href = STATUS_URL;
link.target = "_blank";
link.rel = "noopener noreferrer";
link.setAttribute("aria-label", "Service uptime status");
const badge = document.createElement("img");
badge.src = BADGE_URL;
badge.alt = "Uptime";
badge.width = 120;
badge.height = 20;
link.appendChild(badge);
footer.appendChild(link);
document.body.appendChild(footer);
}
bootstrap().catch(console.error);
You can also call back to JavaScript from Rust to append the badge, using wasm-bindgen's web_sys bindings:
// src/lib.rs
use wasm_bindgen::prelude::*;
use web_sys::{window, Document, HtmlElement};
#[wasm_bindgen]
pub fn run_app() {
let window = window().expect("no global window");
let document = window.document().expect("no document");
// Your WASM application initialization
let app_div = document
.get_element_by_id("app")
.expect("no #app element")
.dyn_into::<HtmlElement>()
.unwrap();
app_div.set_inner_text("WASM application running.");
}
Step 5: Set Up Alert Channels
In Vigilmon's Alert Channels settings:
Email Alerts
- Alert Channels → Email → add your on-call address
- Attach the channel to both HTTP monitors and the heartbeat monitor
Slack Alerts
- Create a Slack Incoming Webhook for your
#alertschannel - Alert Channels → Webhook → paste the Slack webhook URL
- Use this payload template:
{
"text": "🚨 *{{ monitor.name }}* is DOWN\n{{ monitor.url }}\nStatus: {{ event.status }}\n<https://vigilmon.online|Open Vigilmon>"
}
Step 6: Verify Everything Works
# 1. Confirm health endpoint returns 200
curl -s https://yourapp.com/health | jq .status
# 2. Simulate a failure — break your DB connection string and redeploy
# Expected: health endpoint returns 503; Vigilmon alerts within ~2 minutes
# 3. Remove VIGILMON_HEARTBEAT_URL from the worker and run one cycle
# Expected: heartbeat alert fires after the grace window expires
# 4. In Vigilmon → "Test Alert" to confirm Slack/email delivery
Summary
| Monitor | What It Catches | |---|---| | HTTP app check | CDN failures, WASM bundle serving issues | | HTTP health API | Database, API dependencies, backend failures | | Heartbeat | Worker crashes, silent data processing failures |
Next Steps
- Create separate Vigilmon projects for staging and production
- Use Vigilmon's response time graphs to detect backend API latency regressions that would stall WASM data processing
- Configure escalating alerts: email for recoveries, Slack for active outages, PagerDuty for SLA-critical monitors
Ready to get started? Sign up for Vigilmon free — have your first monitor running in under 5 minutes.