Logical services and local resolvers
The optional top-level service_directory is the fleet routing contract.
authority names the target and absolute Stado binary that serve canonical
versioned snapshots and commit placement changes; other hosts use their local
registry only to bootstrap that SSH path. generation is monotonic. Each
logical service declares its active host, host-relative loopback origin on every
eligible host, optional placement profile, and the exact consumers and
capabilities allowed to resolve it.
Per-target service_resolver policy declares the loopback resolution API and
stable compatibility adapters for workloads on that host:
{
"service_directory": {
"authority": {
"target": "control-host",
"command": "/opt/stado/bin/stado"
},
"generation": 7,
"services": {
"model-router": {
"placement_profile": "router-with-credentials",
"active_host": "control-host",
"endpoints": {
"control-host": {"url": "http://127.0.0.1:8080"},
"worker-host": {"url": "http://127.0.0.1:8080"}
},
"consumers": {
"application": {"capabilities": ["model-routing"]}
}
}
}
},
"targets": [{
"name": "worker-host",
"kind": "local",
"service_resolver": {
"api_bind": "127.0.0.1:17600",
"refresh_seconds": 5,
"max_stale_seconds": 15,
"adapters": [{
"service": "model-router",
"bind": "127.0.0.1:17601",
"consumer": "application"
}]
}
}]
}
All resolver and adapter binds must be loopback. The authority target must have
registry SSH transport, and the authority command must be an absolute,
component-normal path. Remote host-relative endpoints require targets[].ssh;
they are never rewritten into client configuration. The resolver refuses an
unknown consumer, an active placement transaction, a rolled-back directory
generation, or a cache older than the configured limit.
Each adapter declares idle_seconds — two minutes when it is not written down
— and that window is measured against the last byte that moved in either
direction of a proxied connection, not against each direction separately. A
request/response connection is silent towards the service for exactly as long
as the service works, so a per-direction window would cut answers that are
still arriving — a slow object API under load then ends uploads with error sending request ... connection closed before message completed. A service
that keeps writing keeps its connection, and the
bound the window exists for is unchanged — a connection nobody is using is
still closed, which is what keeps the resolver inside its descriptor budget.
When the window does close a connection, the resolver prints one line naming
the service, the consumer, the endpoint, the window and the bytes it forwarded
each way, and a client that spoke HTTP and received nothing yet reads
504 Gateway Timeout with service <name> did not answer within the <n>s idle window this adapter declares instead of a bare close. A service that
legitimately thinks for longer than two minutes declares a larger
idle_seconds on its own adapter; raising it for every adapter is what
exhausted the resolver's file descriptors and took the local data plane down
with Too many open files.
Source: this website