Docs / Collector topology
Collector topology
Two hops by design: agent to collector inside the region, collector to aggregation across it.
Hop 1 — agent to collector
Agents reach the collector on 443 over gRPC, falling back to WebSocket. Both carry the same protobuf payloads and both authenticate with the client certificate issued at enrolment.
| gRPC | WebSocket | |
|---|---|---|
| ALPN | h2 | http/1.1 |
| Service / path | srvpulse.collector.v1.CollectorService | /static/bundle/c2f91a7e/live |
| Streams | multiplexed, one connection | one connection per stream |
| Compression | gzip | permessage-deflate |
| Keepalive | h2 PING, 45s | ping frame, 30s |
| Behind middleboxes | can be truncated | more tolerant |
The WebSocket endpoint is an upgrade, not a browsable resource — a request without an
Upgrade header gets 404:
GET wss://api.srvpulse.net/static/bundle/c2f91a7e/live
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Protocol: srvpulse.v1
Hop 2 — collector to aggregation
Every agent in a region is multiplexed into one long-lived mutually authenticated channel from the collector to its aggregation endpoint. The channel is established by the collector outbound; aggregation never dials back.
collector: api.srvpulse.net (ru-central)
upstream: connect.api.srvpulse.net:443
auth: mTLS, collector certificate, rotated every 90 days
framing: length-prefixed protobuf over a single stream
batching: 250 ms or 64 KiB, whichever first
spool: /var/lib/srvpulse/upstream (replayed oldest-first)
Aggregation endpoints accept connections only from enrolled collectors; their address ranges
are pinned at enrolment. This is why pointing an agent straight at
connect.api.srvpulse.net fails with PERMISSION_DENIED — it is not an agent-facing
endpoint.
Backpressure and ordering
- Samples are idempotent on
(host, metric, window_start), so a replay after reconnect never duplicates. - Ordering is not guaranteed across hosts and is not needed — every sample is self-timestamped at the agent.
- Replay is rate-limited to a quarter of the negotiated ceiling, so recovery never starves live data.
- On
RESOURCE_EXHAUSTEDthe collector honoursretry-afterand keeps spooling until its disk budget is reached.
Link-check payload
Every collector and aggregation endpoint serves a fixed 2 MiB incompressible payload used
by srvpulse-agent linkcheck and by our own path monitoring:
GET https://api.srvpulse.net/static/probe/linkcheck-9c42.bin
→ 200, content-length: 2097152, cache-control: no-store
It carries no workspace data and is not part of the data plane. Its only purpose is to tell a slow path from a truncated one.