Resolves logical service names to reachable instances, balances across them, and learns from reported call outcomes.
Registered under CAPABILITIES.SERVICE_DISCOVERY.
Calling a service, with failover
Calling a service, with failover
const discovery = ctx.services.get<IServiceDiscovery>( CAPABILITIES.SERVICE_DISCOVERY, ); const instance = await discovery.pick('billing'); if (instance === null) throw new Error('no billing instance'); try { const url = await discovery.resolveUrl('billing', '/invoices'); const response = await fetch(url!); discovery.report(instance, response.ok ? 'success' : 'failure'); } catch (error) { discovery.report(instance, 'failure'); throw error; }
resolve(serviceName: string): Promise<readonly ServiceInstance[]>
Lists every instance discovery knows for a service.
Reports what the backend says, so ejected instances are included —
ejection is a IServiceDiscovery.pick concern, not a knowledge
one. An unknown service name resolves to an empty list rather than
throwing.
pick(serviceName: string,options?: PickOptions): Promise<ServiceInstance | null>
Chooses one instance, skipping ejected ones.
resolveUrl(): Promise<string | null>
Formats IServiceDiscovery.pick's choice as an absolute URL.
report(instance: ServiceInstance,outcome: ServiceOutcome): void
Reports how a call to an instance went.
Enough failures inside the configured window eject the instance from
IServiceDiscovery.pick's pool; a success clears its window and
un-ejects it immediately. Ejection state is per-process.
watch(serviceName: string,listener: (instances: readonly ServiceInstance[]) => void): Promise<Unsubscribe>
Subscribes to instance-list changes for a service.
Push-based where the backend supports it (Consul blocking queries, Kubernetes watch streams) and interval-polled where it does not (DNS, static). The listener receives the full current list, never a delta.