EdgeNodeNotReady, ProbeNodeCheckFailing, NATSServerDown,
EtcdMembersDown, IngestWebErrorRatioHigh, IngestOTLPErrorRatioHigh (alerts.md).
Conventions (node names, addresses, compose directories) are in overview.md.
What protects ingestion while you work
- Port 80 of every node answers the node’s composite health: 308 healthy, 503 not
(../deploy/ansible.md section 5). Traffic Manager probes port 80 every
10 s and drops a node after three failed probes from the
inandotlpanswers (answer TTL 10 s). A browser that cannot connect to one address tries the next. - NATS keeps every stream at three replicas; two of three servers keep publishing. etcd keeps Patroni’s leader key with two of three members.
- The configured window for clients pinned to a dead address is up to about 45 s
(../reference/availability.md); the staging drill measures
it.
az network traffic-manager endpoint list -g veristar-<env> --profile-name <domain>-<env>-in --type externalEndpoints -o tableshows each node’s monitor status.
Steps
-
Find the node. From the alert labels, or from outside:
Expected on a healthy node:
308. A failing node answers503(a check failed, or the node is drained) or does not connect. -
Take it out of DNS on purpose if it is up but misbehaving (wrong answers, high latency),
so Traffic Manager stops sending traffic to it while you work:
Expected:
503at once. Wait 120 s before stopping anything (three 10 s probes, the 5 s timeout and the 10 s answer TTL, with margin; the same waitdeploy.ymluses). -
See which part fails. On the node:
/edgezis the composite answer behind port 80 (gateway ready, collector health check, local NATS current with a meta leader). Every service must showrunning (healthy)inps, apart fromgatewayandcollector, which have no compose health check. -
Restart what is down, one service at a time, and read its log first:
natsdown: start it; it rejoins and catches up. Never delete a NATS store while another NATS server is also down (NATSQuorumLost in alerts.md).etcddown: start it. If two members are down, Patroni cannot renew its leader key and the primary demotes itself after 30 s; start the members before anything else.gatewaynot ready withdaily_secretsfailing: see VisitorSecretMissing in alerts.md.- After a power loss Docker starts the projects through
sa-edge-start.service(installed by the edge role because a start that fails during daemon start-up is not retried by the restart policy). Check it withsystemctl status sa-edge-start.service.
-
Put it back. When
/edgezanswers and port 80 would be healthy:Expected:308. Traffic Manager adds the address back after its next successful probe. -
Check the cluster from a core node:
(production:
10.10.1.11). Expected: a"meta_cluster"object with a"leader"and three replicas, all current. The node’s own/healthzanswers{"status":"ok"}:
A node that is gone for good
The VM is lost (deleted, or unbootable). Replace it with OpenTofu, keeping its public IPv4 address, which is a separate resource and survives the VM, so the Traffic Manager endpoint stays valid:-
Plan the replacement of that one server (staging shown; the node name is the inventory name):
Expected:
Plan: 1 to add, 0 to change, 1 to destroy.with only that VM. Production VMs carry a delete lock, so the apply fails there untilprotectis turned off for that apply (../deploy/opentofu.md). -
make staging-apply. Expected:Apply complete!and a rewritteninfra/ansible/inventories/staging/hosts.json. -
Converge:
make staging-deploy SA_IMAGE_TAG=<release tag> SA_RELEASE_MANIFEST=<release-images.json>(see ../deploy/ansible.md). NATS on the new node starts with an empty store and catches up from the other two, because a JetStream peer is identified by its server name. -
etcd rejoins on its own. The edge role (
roles/edge/tasks/etcd.yml) sees that the new node has no etcd data volume while the other two members answer, removes the stale member of this node’s name (or an unstarted member at its address) through a healthy peer, adds the node again and starts it with--initial-cluster-state=existing. It records that in/etc/veristar/edge/etcd-initial-state, so later converges change nothing. Check from any edge node that three members arestartedand healthy:If the converge failed between the member add and the start, converge again: the unstarted member at this address is removed and added once more. If only the etcd volume of a running node was lost, delete the marker file on that node first, so the role decides again.
Exercised
Not yet exercised: the automatic etcd rejoin of step 4 (
make ops-local steps rebuild-edge3
and etcd drive it, but the run of 2026-11-13 was stopped before them, see the O-6 resolution
in docs/audit/functional-audit-ops.md), the manual drain and undrain of steps 2 and 5 by hand (the same flag file was
used by deploy.yml in the local converge), removal by Traffic Manager, and the
replacement of a lost node (both need staging). The multi-node topology cannot
run on the shared development host, so none of this was repeated in phase 19.