Aller au contenu
Français

Management overview

Ce contenu n’est pas encore disponible dans votre langue.

managementRoutes(...) builds a route tree of operational endpoints. You bind it on its own port (8558 by convention), separate from your app’s main HTTP server, exposing:

  • Health probes — liveness + readiness for K8s.
  • Cluster info — members, leader, sharding regions.
  • Metrics — Prometheus exposition (optional).
  • Admin endpoints — leave / down (optional, off by default).
import { managementRoutes } from 'actor-ts';
// Build the routes (cluster is optional — pass null to skip /cluster/*),
// then bind them on a dedicated port.
const { routes, health } = managementRoutes(system, cluster, {
enableMetricsEndpoint: true,
});
const binding = await system.http(8558, { host: '0.0.0.0' }).bind(routes);
// management endpoints now serve on http://0.0.0.0:8558

managementRoutes returns { routes, health }: routes is the Route tree you bind, and health is the HealthCheckRegistry you register liveness / readiness checks on.

The third argument is ManagementRoutesOptions — endpoint toggles and optional middleware. The port and host are not settings: they go to system.http(port, { host }), and the cluster is the second positional argument.

type ManagementRoutesOptionsType = {
enableLeaveEndpoint?: boolean; // POST /cluster/leave (default false)
enableDownEndpoint?: boolean; // POST /cluster/down (default false)
enableMetricsEndpoint?: boolean; // GET /metrics (default false)
auth?: Middleware; // guards /cluster/* (+ /metrics)
ipAllowlist?: Middleware; // guards EVERY endpoint, incl. /health + /ready
authProtectHealth?: boolean; // also require `auth` on /health + /ready (default false)
};

A typical production wiring:

const { routes, health } = managementRoutes(system, cluster, {
enableMetricsEndpoint: true, // for Prometheus
enableLeaveEndpoint: false, // admin-only; gate behind auth
enableDownEndpoint: false,
});
await system.http(8558).bind(routes);
EndpointAlways on?Purpose
GET /healthLiveness — 200 iff every liveness check passes.
GET /readyReadiness — 200 iff cluster up + every readiness check passes.
GET /cluster/membersWhen cluster is setMembership JSON.
GET /cluster/leaderWhen cluster is setLeader address.
GET /cluster/shards?type=<name>When cluster is setShard placement for a sharded type.
POST /cluster/leaveOpt-in (enableLeaveEndpoint)Trigger graceful cluster-leave.
POST /cluster/downOpt-in (enableDownEndpoint)Force-down a peer by address.
GET /metricsOpt-in (enableMetricsEndpoint)Prometheus text format.

See HTTP endpoints for the full surface + response shapes.

const { routes, health } = managementRoutes(system, cluster);
// Readiness — gates traffic; return { name, status, detail? }.
health.addReadiness(async () => {
const ok = await db.ping();
return { name: 'database', status: ok, detail: ok ? undefined : 'db unreachable' };
});
await system.http(8558).bind(routes);

Checks plug into /health (liveness) and /ready (readiness). A failing check makes that endpoint return 503. See Health checks.

# In your pod spec:
readinessProbe:
httpGet:
path: /ready
port: 8558
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8558
initialDelaySeconds: 30
periodSeconds: 10

K8s polls these endpoints to decide if the pod should receive traffic (ready) or be restarted (live). See Kubernetes deployment for the full deployment recipe.

App port (8080): public, behind a load balancer
Management (8558): internal-only, firewalled off

The management endpoints reveal internal state — cluster member addresses, metric values, etc. Exposing them publicly is a security risk. Bind them on a separate port and firewall it internally.

In K8s, this is per-pod — probes hit :8558 from the kubelet (same node), but no Service exposes it externally.

For more access control:

# In your Service / Ingress config:
# - 8080 → public
# - 8558 → not exposed publicly; mTLS internally

Some production setups expose management behind a side-car proxy that handles auth (Envoy + JWT, Linkerd + mTLS). Alternatively, attach the built-in auth / ipAllowlist middleware via the settings (see HTTP endpoints).

managementRoutes returns plain routes, so you don’t need a dedicated port at all — concat them into your app’s existing HTTP routes:

import { managementRoutes, concat } from 'actor-ts';
const { routes: mgmt } = managementRoutes(system, cluster);
await system.http(8080).bind(concat(appRoutes, mgmt));

Two reasons you might do this instead of a separate port:

  1. You already have an HTTP server and want management inline.
  2. Single-node app without cluster — health checks alone might not justify the extra port; wire /health into your existing server.

(Mounting management on the public port re-exposes internal state — gate it with the auth / ipAllowlist settings if you do.)