Service Registry
The service_registry table is the BE's live map of the platform: which
services exist, where they listen, what they can do, and whether they're
actually alive. It is event-fed — the BE never polls services; they
announce themselves.
Inbound lifecycle — ServiceLifecycleSubscriber
Shielded NATS subscriptions (publisher-identity verifies the sender is
a registered service before any handler runs):
| Subject | Effect |
|---|---|
service.register | upsert the registry row — code, base_url, version, capabilities, endpoints; then MCP discoverEntitiesFromService learns the service's entities and serviceEventsBus fans out to dependents |
service.heartbeat | refresh last_health_check_at + health flags |
service.unregister | mark the service gone — proxy closes its /ws/<code> routes, dependents (e.g. AI docs ingest) drop its data |
service.stale | self-reported degradation |
Status derivation
Code
Stale detection — stale-detection-job
A watchdog job scans the registry: any row whose last_health_check_at
is older than 90s (3× the heartbeat interval) is stale. Two alarm
modes:
- some stale → those services degraded; proxy returns 503 for them.
- ALL stale simultaneously → a single CRITICAL alarm (once per outage): likely a NATS outage rather than N independent crashes.
client_shield_registry
A parallel table: the known client identities (services + FE/BE
themselves) used by the client-identity gate — inbound internal calls
must present a User-Agent matching a registered client plus the
client-shield secret. client_shield_registry.get is the governed NATS lookup
US services use for the same gate.
Consumers
- Proxy —
/ws/:code/*forwards only to registered, enabled, routable services. - MCP — entity discovery per registered service; the tool catalog grows/shrinks with the registry.
- Settings → Modules — the admin UI reads
service_registryfor the live/stale/offline/unhealthy display (see the user-guide page). - AI —
docs_packcapability in the register payload drives the docs-pack pull; unregister cleans the KB.