The registry exposes a small node discovery API consumed by TrayApplication.
All endpoints are rooted at /nodes.
| Method | Path | Purpose |
|---|---|---|
PUT |
/nodes/register |
Register a node or refresh its advertised address. |
PUT |
/nodes/heartbeat |
Refresh liveness and advertise whether the node has source work. |
GET |
/nodes |
List currently active nodes. |
PUT /nodes/register
Content-Type: application/jsonRequest:
{
"nodeId": "550e8400-e29b-41d4-a716-446655440000",
"ip": "192.168.1.42",
"port": 8080
}Validation:
| Field | Rule |
|---|---|
nodeId |
Required UUID. |
ip |
Required non-blank string. |
port |
Integer from 1 to 65535. |
Response:
{
"registered": true,
"alreadyKnown": false,
"nodeId": "550e8400-e29b-41d4-a716-446655440000",
"registeredAt": "2026-06-21T12:00:00Z"
}Registering the same nodeId again updates the advertised IP/port and returns
alreadyKnown: true. Re-registering also clears any previous hasJob=true
state for that node.
Invalid requests return 400 Bad Request.
PUT /nodes/heartbeat
Content-Type: application/jsonRequest:
{
"nodeId": "550e8400-e29b-41d4-a716-446655440000",
"ip": "192.168.1.42",
"port": 8080,
"hasJob": true
}Validation:
| Field | Rule |
|---|---|
nodeId |
Required UUID. |
ip |
Required non-blank string. |
port |
Integer from 1 to 65535. |
hasJob |
Boolean. |
Response for a known node:
{
"acknowledged": true,
"nodeId": "550e8400-e29b-41d4-a716-446655440000",
"lastSeen": "2026-06-21T12:00:01Z",
"jobNodeUrls": [
"http://192.168.1.42:8080"
]
}jobNodeUrls contains active nodes that most recently heartbeated with
hasJob=true. The URLs are built as:
http://{ip}:{port}
If hasJob=false, the registry removes the node from the advertised job-source
set.
Responses:
| Status | Meaning |
|---|---|
200 OK |
Heartbeat accepted for a registered node. |
400 Bad Request |
Request body failed validation. |
404 Not Found |
Node is unknown; register before sending heartbeats. |
GET /nodesResponse:
[
{
"nodeId": "550e8400-e29b-41d4-a716-446655440000",
"ip": "192.168.1.42",
"port": 8080,
"lastSeen": "2026-06-21T12:00:01Z"
}
]Only nodes whose lastSeen is within registry.staleness-threshold-ms are
returned. registeredAt is intentionally not included in this list response.
- The registry keeps state in memory.
- A node is active while its latest heartbeat is within the staleness threshold.
- A scheduled cleanup removes very old nodes after ten times the staleness threshold.
- The registry does not contact TrayApplication nodes directly; nodes pull
discovery data from the registry through heartbeats and
GET /nodes.