Architecture
The services that make up Pulsimo, where data lives and how a check becomes an alert.
Pulsimo is a set of small Rust services and a Next.js web app, started together with Docker Compose. Configuration, checks, incidents and users live in PostgreSQL; metrics in VictoriaMetrics; logs in VictoriaLogs. Redis carries events between the services.
The big picture#
┌────────────── your systems ──────────────┐
│ websites · APIs · databases · Redis │
│ exporters and app /metrics · log files │
└───────┬──────────────┬──────────────┬────┘
checks │ scrapes│ Fluent Bit│ (HTTPS, plog_ token)
▼ ▼ ▼
┌─────────┐ ┌──────────────┐ ┌─────────────┐
│ checker │ │ metrics- │ │ api-gateway │◄── web app (frontend)
└────┬────┘ │ collector │ └──────┬──────┘ and API clients
│ └──────┬───────┘ │
events (Redis) │ │ │
▼ ▼ ▼
┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ notification │ │VictoriaMetrics│ │ VictoriaLogs │
└──────┬───────┘ │ + vmalert │ └──────────────┘
│ └───────────────┘
▼ PostgreSQL holds configuration,
Slack · Discord · Teams · checks, incidents, alarms and users
Google Chat · email · webhooksServices#
| Service | Role |
|---|---|
frontend |
The web app. Talks only to the API gateway |
api-gateway |
REST API and live updates (WebSocket) for the web app and API keys; sign-in and access checks; log ingestion; organization-scoped queries to the metrics and log stores |
checker |
Runs every endpoint's checks on its own schedule; evaluates monitors that use metrics; writes check results to PostgreSQL and as metrics |
metrics-collector |
Scrapes metric sources; discovery of routes, databases, hosts and containers; change detection; SLOs, anomalies, capacity forecasts; alarm rules; log patterns and incidents from logs |
notification |
Turns events into alarms and messages: routing, reminders, deploy grace, digests, delivery to each platform |
dependency-tracker |
Builds the dependency map between services |
maintenance-scheduler |
Retention, hourly roll-ups and database upkeep on cron schedules |
migrations |
Applies database migrations on start, then exits |
postgres |
Configuration, check results, incidents, alarms, users, the event trail |
redis |
Events between services and live updates to the browser |
victoriametrics |
All metric series, scraped and Pulsimo's own |
victorialogs |
Log lines; each organization is a separate tenant |
vmalert |
Evaluates the recording rules the collector generates, every 30 s |
From a check to an alert#
- The checker keeps every endpoint's next check time in memory and starts checks as
they come due, at most
MAX_CONCURRENT_CHECKSat once. A slow endpoint never delays the others, and one endpoint never has two checks running at the same time. - Results are saved in batches and also written to VictoriaMetrics as
pulsimo_check_up,pulsimo_check_duration_secondsand friends. - When an endpoint reaches its alert policy's failures, the checker opens an incident and publishes an event on Redis.
- An alarm opens and the notification service picks the channels (rule or policy first, then each channel's severity, projects and categories), and sends the message with what the linked metrics and logs show.
- If a deploy or restart of a linked source happened in the last 3 minutes, the message is held and sent only if the endpoint is still down. If a service it depends on is already down, it is held until that one recovers.
- While the incident is open, the metrics-collector scrapes the linked sources every 5 seconds for 30 minutes and saves the evidence, so the incident keeps its charts after the metrics retention has passed.
Metrics#
The collector pulls each source on its own interval and stores samples in
VictoriaMetrics with labels such as org_id, source_id, job and instance, and
project_id and endpoint_id when set. These labels override any label of the same name
sent by the exporter, and the gateway adds the organization to every query, so one
organization never sees another's series. More in Metric sources.
Logs#
Fluent Bit (or curl, Loki push, Elasticsearch bulk or OTLP/HTTP) sends lines to
POST /api/v1/logs/ingest with a source's plog_ token. The gateway checks the token,
applies the source's rate limit, normalizes fields such as level, service and
container, redacts secrets, and writes to VictoriaLogs under the organization's tenant.
The collector groups warning and error lines into patterns and opens
incidents from logs. More in Logs.
Design choices#
- Detect from metrics, not agents. Deploys, restarts, new routes and dependencies are inferred from what exporters already expose, so nothing extra is installed.
- Hold, don't silence. Deploy grace and maintenance windows delay and re-check instead of hiding alerts, so nothing is lost if the service stays down.
- Keep evidence. A small, downsampled copy of the metrics around each incident is saved in PostgreSQL and outlives the metrics retention.
- Best effort around the core. A slow or missing metrics store never delays an active check's verdict or an alert.
Ports#
| Port | Service | Exposed on the host |
|---|---|---|
| 3000 | frontend | Yes (EXPOSE_FRONTEND_PORT) |
| 8080 | api-gateway | Yes (EXPOSE_API_PORT) |
| 5432 | postgres | Yes by default; close it in production |
| 6379 | redis | Yes by default; close it in production |
| 8081 to 8084, 3007 | checker, notification, dependency-tracker, metrics-collector, maintenance-scheduler | No |
| 8428, 9428, 8880 | victoriametrics, victorialogs, vmalert | No |