POST /registry/heartbeatExtends the session's lease by expiresInMs, replaces its headroom and draining state, re-probes the advertise URL, and returns pending control messages. A session with no heartbeat for one lease is dead: its placements re-place on the next request.
Authentication
pinboard:worker scope, same account (sub) that registered the session. The principal's claim must still cover every namespace, hostname and env of the registration.
Request body
application/json, at most 1 MiB.
| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | From register. |
headroom | number | Yes | Current free capacity. Replaces the stored value; each new placement decrements it until the next heartbeat. |
draining | boolean | Yes | The worker's own drain flag. |
challenge | string | Yes | Token for this heartbeat's probe. Rotate per heartbeat. |
challengeValue | string | Yes | Expected answer. |
acks | string[] | No | msgIds of control messages the worker has applied. |
Probe
Each heartbeat calls GET {advertiseUrl}/_pinned/challenge?challenge={challenge}, as in register.
| Probe result | Effect |
|---|---|
Answers challengeValue | Lease renewed. Clears degraded. |
Unreachable, non-2xx, or body not received | Lease renewed, record marked degraded (degradedSince). Existing placements keep routing; no new placements. Ack carries degraded: true. |
| Answers a different value | Registration voided: records dropped, 409 with reregister. The URL reaches another worker, typically a shared load balancer. |
Control messages
Pinboard queues messages per session and re-delivers them on every heartbeat until the worker lists their msgId in acks. The queue expires two leases after its last write or read.
| Field | Type | Description |
|---|---|---|
msgId | string | 16 hex characters. Ack it once applied. |
type | "wind_down" | The only type. |
ns | string | Namespace. |
id | string | Instance id. |
deadline | number | null | Seconds from now until the placement is freed, computed at delivery; 0 once passed. null revokes an earlier wind-down. |
Example
curl -X POST https://pinboard.example.com/registry/heartbeat \
-H "Authorization: Bearer $PINBOARD_WORKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "3f9c0d6e2b1a4c7d8e9f0a1b2c3d4e5f",
"headroom": 96,
"draining": false,
"challenge": "e2a71c0d9f3b4a58",
"challengeValue": "4c8d2b6f1e0a7c39",
"acks": ["9a1b2c3d4e5f6071"]
}'Response
200
| Field | Type | Description |
|---|---|---|
expiresInMs | integer | Lease length from now. |
draining | boolean | Own draining or an operator drain on the clientId. |
drainDeadline | number | Only while draining under a timed operator drain: seconds until forced release, 0 once passed. |
degraded | true | Only when this heartbeat's probe failed. |
messages | object[] | Only when non-empty. Control messages above. |
{
"expiresInMs": 15000,
"draining": false,
"messages": [
{
"msgId": "0f1e2d3c4b5a6978",
"type": "wind_down",
"ns": "/threads",
"id": "t_8f2a",
"deadline": 29.4
}
]
}Under a timed operator drain the lease stops advancing past the drain deadline plus one lease.
Errors
| Status | Body | When | Worker should |
|---|---|---|---|
401 | {"error":"unauthorized"} | No accepted credential | Fix the token |
403 | {"error":"forbidden"} | Missing scope, other account, or the claim no longer covers the registration | Retry; check the token |
503 | {"error":"not the serving fleet"} | Node not serving | Retry after Retry-After |
413 / 400 | body too large / invalid json | Fix the request | |
400 | {"error":"expected { sessionId, headroom, draining, challenge, challengeValue, acks? }"} | Schema failure | Fix the request |
409 | {"error":"unknown session","reregister":true} | Session unknown or lease expired | Register again with prevSessionId and instances |
409 | {"error":"registration voided: challenge value mismatch on the advertise URL","reregister":true} | Probe reached another worker | Fix advertiseUrl, then register |
409 | {"error":"registration superseded: {hostname}{ns} now bound to env {env} at epoch {n}","superseded":true} | Hostname-aware: a higher-epoch registration took the binding. Records dropped. | Stop registering |