Yew is a modern Rust framework for building multi-threaded front-end web applications compiled to WebAssembly. It brings Rust's memory safety and performance guarantees to the browser, enabling component-based UIs with the power of a systems language. But Wasm-based UIs still depend on backend APIs, databases, and background services — and those 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 Yew backend API server - Vigilmon HTTP monitors for your app and API
- A heartbeat monitor for background jobs
- Alert channels (email and Slack)
- An uptime badge rendered in your Yew component tree
Prerequisites
- A Yew project with a backend API (Axum, Actix-web, or Rocket)
- A free Vigilmon account
Step 1: Add a Health Endpoint
Your Yew WASM bundle is served as static assets, but your backend API server needs a health endpoint that Vigilmon can poll continuously. Here's an example with Axum:
// src/main.rs (backend with Axum)
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;
}
}
// Cache check (e.g. Redis)
match check_cache().await {
Ok(_) => { checks.insert("cache".into(), json!("ok")); }
Err(e) => {
checks.insert("cache".into(), json!(format!("error: {}", e)));
degraded = true;
}
}
let status_code = if degraded { StatusCode::SERVICE_UNAVAILABLE } else { StatusCode::OK };
let body = json!({
"status": if degraded { "degraded" } else { "ok" },
"checks": checks,
});
(status_code, Json(body))
}
async fn check_database() -> Result<(), String> {
// pool.acquire().await.map_err(|e| e.to_string())?;
Ok(())
}
async fn check_cache() -> Result<(), String> {
// redis_client.ping().await.map_err(|e| e.to_string())?;
Ok(())
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/health", get(health_handler))
// Serve your compiled Yew WASM app
.nest_service("/", ServeDir::new("dist"));
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","cache":"ok"}}
Step 2: Configure Vigilmon HTTP Monitors
Log in to Vigilmon → Monitors → New Monitor:
Monitor 1: Yew App (Frontend / WASM Bundle)
| Field | Value |
|---|---|
| URL | https://yourapp.com/ |
| Method | GET |
| Expected status | 200 |
| Expected body | A stable string from your index.html shell |
| 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 |
Separating frontend from API monitoring is especially important for Yew apps: the static WASM bundle may be served from a CDN while the Axum backend runs on a separate host — failures are independent.
Step 3: Heartbeat for Background Tasks
Yew-powered apps often consume data from backend workers — data aggregation pipelines, WebSocket feed producers, or scheduled report generators. A Vigilmon heartbeat monitor detects when these workers stop silently:
// 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 process_data().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 process_data() -> Result<(), Box<dyn std::error::Error>> {
// Your backend data processing logic here
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 in Your Yew Component
Yew uses a JSX-like macro syntax (html!) for building component trees. You can include a Vigilmon status badge as a static leaf node:
// src/components/footer.rs
use yew::prelude::*;
const BADGE_URL: &str = "https://vigilmon.online/api/badge/your-monitor-id.svg";
const STATUS_URL: &str = "https://vigilmon.online/status/your-monitor-slug";
#[function_component(Footer)]
pub fn footer() -> Html {
html! {
<footer class="footer">
<a
href={STATUS_URL}
target="_blank"
rel="noopener noreferrer"
aria-label="Service uptime status"
>
<img
src={BADGE_URL}
alt="Uptime"
width="120"
height="20"
/>
</a>
</footer>
}
}
// src/app.rs
use yew::prelude::*;
use crate::components::footer::Footer;
#[function_component(App)]
pub fn app() -> Html {
html! {
<div class="app">
<main>
<p>{ "Your content here." }</p>
</main>
<Footer />
</div>
}
}
Yew's virtual DOM only re-renders components when their props or hooks change — the static Footer component with no props is never re-rendered during data updates, so the badge image is never refetched.
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 the heartbeat URL env var and let the worker 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, cache, and backend dependency failures | | Heartbeat | Worker crashes, silent data pipeline failures |
Next Steps
- Create separate Vigilmon projects for staging and production
- Use Vigilmon's response time graphs to correlate backend API latency with Yew component re-render frequency
- 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.