@fluojs/terminus
v1.0.5
Published
Health indicator composition and enriched runtime health aggregation for Fluo applications.
Downloads
363
Maintainers
Readme
@fluojs/terminus
Health indicator toolkit for fluo applications. @fluojs/terminus layers on top of runtime health/readiness endpoints to provide dependency-aware status reporting.
Table of Contents
- Installation
- When to Use
- Quick Start
- Common Patterns
- NestJS Migration Boundaries
- Public API Overview
- Related Packages
- Example Sources
Installation
pnpm add @fluojs/terminusInstall the optional peer only when you use the Redis indicator subpath:
pnpm add @fluojs/redis ioredisWhen to Use
- When you need to monitor external dependencies (databases, Redis, APIs) as part of your application's health status.
- When you want a structured JSON health report that aligns with standard monitoring patterns.
- When you need your
/readycheck to leave rotation while required downstream readiness signals are unavailable.
Quick Start
Import TerminusModule.forRoot() to register health indicators.
import { Module } from '@fluojs/core';
import { HttpHealthIndicator, TerminusModule } from '@fluojs/terminus';
import { MemoryHealthIndicator } from '@fluojs/terminus/node';
@Module({
imports: [
TerminusModule.forRoot({
indicators: [
new HttpHealthIndicator({ key: 'upstream-api', url: 'https://example.com/health' }),
new MemoryHealthIndicator({ key: 'memory', heapUsedThresholdRatio: 0.9 }),
],
}),
],
})
class AppModule {}Common Patterns
Built-in Indicators
The package provides several indicators out of the box:
PrismaHealthIndicator/DrizzleHealthIndicatorRedisHealthIndicator(from@fluojs/terminus/redis)HttpHealthIndicatorMemoryHealthIndicator(root-exported for compatibility and also available from@fluojs/terminus/node)DiskHealthIndicator(root-exported for compatibility and also available from@fluojs/terminus/node)
DI-Backed Indicators
To use indicators that require dependencies from the DI container (like Redis or Database clients) without importing peer dependencies at module load time, use the documented provider factories. These helpers create indicator provider entries for TerminusModule.forRoot({ indicatorProviders }); they do not replace the module facade.
import { TerminusModule } from '@fluojs/terminus';
import { createRedisHealthIndicatorProvider } from '@fluojs/terminus/redis';
TerminusModule.forRoot({
indicatorProviders: [
createRedisHealthIndicatorProvider({ key: 'redis' })
],
});Omit clientName to keep probing the default Redis client. If the indicator should use a named Redis connection, pass clientName so the provider resolves that named client token instead of the default one.
TerminusModule.forRoot({
indicatorProviders: [
createRedisHealthIndicatorProvider({ key: 'redis' }),
createRedisHealthIndicatorProvider({ clientName: 'cache', key: 'cache-redis' }),
],
});Redis indicators created through @fluojs/terminus/redis are lifecycle-aware when they receive a client from @fluojs/redis. Terminus maps the Redis connection state with createRedisPlatformStatusSnapshot(...) before sending PING, so clients in wait, connecting, reconnecting, close, or end states mark /health and /ready unavailable instead of relying on a raw ping alone. Custom ping callbacks remain supported for manual probes, but lifecycle metadata is only attached when a Redis client exposes its status.
For Drizzle, createDrizzleHealthIndicatorProvider() prefers the lifecycle-aware DrizzleDatabase wrapper exported by @fluojs/drizzle. The indicator reports down before probing SQL whenever Drizzle is shutting down, stopped, or otherwise not ready according to DrizzleDatabase.createPlatformStatusSnapshot(). If only the legacy raw DRIZZLE_DATABASE handle is registered, the provider keeps the previous lightweight SQL probe behavior.
Provider factories are repeatable. You may register multiple providers created by the same factory in one indicatorProviders array when each instance uses a distinct indicator key or dependency option; Terminus keeps every provider instance under its own DI token instead of letting later same-type providers overwrite earlier ones.
Execution Guardrails
Use execution.indicatorTimeoutMs when custom indicators might hang or depend on slow downstreams. When a probe exceeds the configured timeout, Terminus marks that indicator as down instead of waiting forever.
Terminus also serializes checks per indicator instance. If a timed-out or otherwise slow probe is still running when another /health or /ready request arrives, Terminus reports that indicator as down for the new request instead of starting an overlapping probe against the same downstream. Built-in HTTP indicators abort their fetch request when their own timeout expires; other drivers and custom callbacks may not expose cancellation, so they are protected from overlap until the original promise settles.
TerminusModule.forRoot({
execution: {
indicatorTimeoutMs: 1_500,
},
indicators: [
new HttpHealthIndicator({ key: 'upstream-api', url: 'https://example.com/health' }),
],
});Use path to mount the health endpoints under a custom path, and readinessChecks to compose application-specific readiness logic with Terminus indicator and platform readiness checks.
Failure Semantics
When an indicator returns a down result or throws a HealthCheckError, the TerminusHealthService aggregates the failure into a report:
/healthreturns HTTP503if any indicator fails./readyreturns HTTP503when registered indicators fail, a custom readiness check returnsfalse, runtime shutdown has begun, or platform readiness is anything other thanready. Platformcriticalmetadata is preserved in diagnostics, but the HTTP readiness endpoint itself is a binary ready/unavailable gate and does not expose warning severity buckets.- The response body contains a structured JSON object with
status,contributors,info,error, anddetails. - Indicators may emit multiple keyed entries in a single check result;
/healthpreserves every keyed entry indetailsand in thecontributors.up/contributors.downsummaries. - Unsupported, empty, or non-object indicator results are reported as
downdiagnostics instead of being silently discarded. - Blank indicator result keys are reported as
downdiagnostics instead of contributing healthy entries. - If an indicator reuses a key that was already reported earlier in the same run, Terminus keeps the first entry and adds a deterministic
*-duplicate-key-errorcontributor instead of silently overwriting data. - Platform health/readiness failures are surfaced as deterministic
fluo-platform-healthandfluo-platform-readinesscontributors in/healthresponses. These keys are reserved for platform diagnostics; if a user indicator returns one of them during a platform failure, Terminus keeps the platform payload under the reserved key and adds a deterministic*-user-key-collisiondiagnostic instead of dropping runtime state. /healthresponses may include aplatformblock with platform health/readiness details when runtime diagnostics are available.- Drizzle indicators created through the DI provider map Drizzle lifecycle readiness/health state before SQL probing, so shutdown or stopped integrations mark
/healthand/readyas unavailable even if the underlying driver still accepts a raw ping. - Redis indicators created through the Redis subpath map
@fluojs/redisclient lifecycle state beforePING, so shutdown or disconnected Redis clients mark/healthand/readyas unavailable even before command execution.
NestJS Migration Boundaries
When migrating from @nestjs/terminus, treat TerminusModule.forRoot(...) as the primary fluo API. fluo does not model controller-level @HealthCheck() methods that call HealthCheckService.check([...]) as the main application contract. You can still call TerminusHealthService.check() directly from tests or custom application code, but production endpoint registration should keep indicators and readiness hooks in module options so the runtime /health and /ready routes include platform diagnostics consistently.
Terminus also does not create a separate process-only liveness route by default. The default route model remains GET /health for aggregated health and GET /ready for readiness. If your deployment requires a narrow process liveness probe, define that probe at the application or deployment layer instead of assuming Terminus will add a NestJS-style extra route.
Runtime-specific indicators are split by subpath. Use @fluojs/terminus/node for Node.js memory and disk checks, and use @fluojs/terminus/redis for Redis checks. The root package keeps Redis optional-peer imports out of the root entrypoint and keeps Node disk filesystem access lazy so applications opt into runtime-specific probes explicitly.
Public API Overview
TerminusModule
static forRoot(options: TerminusModuleOptions): ModuleType- Main entry point for registering indicators and providers.
- Options include
indicators,indicatorProviders,readinessChecks,execution.indicatorTimeoutMs, andpath.
TerminusHealthService
check(): Promise<HealthCheckReport>- Runs the currently registered indicators and returns the aggregated report.
isHealthy(): Promise<boolean>- Returns whether the current aggregated report is fully healthy.
Direct helpers and tokens
runHealthCheck(...),assertHealthCheck(...): Direct aggregation/testing helpers.TERMINUS_HEALTH_INDICATORS,TERMINUS_INDICATOR_PROVIDER_TOKENS: DI tokens for registered indicators and provider tokens.- Built-in indicators also expose
create*HealthIndicator()andcreate*HealthIndicatorProvider()helpers. Provider helpers are intentional DI-composition exceptions forindicatorProviders, while application registration should still go throughTerminusModule.forRoot(...).
@fluojs/terminus/redis
RedisHealthIndicator,createRedisHealthIndicator(),createRedisHealthIndicatorProvider()- Redis-specific indicator helpers are exported from the dedicated subpath so the root package stays import-safe without the optional Redis peer installed.
- The provider resolves the default
@fluojs/redisclient token by default, or a named token whenclientNameis supplied, and reuses Redis platform status semantics for readiness diagnostics.
@fluojs/terminus/node
MemoryHealthIndicator,DiskHealthIndicator,createMemoryHealthIndicator(),createDiskHealthIndicator(),createMemoryHealthIndicatorProvider(),createDiskHealthIndicatorProvider()- Node-specific indicator helpers remain root-exported for compatibility and are also exported from this dedicated subpath. Filesystem access for disk checks is lazy-loaded so importing the root package does not load Node filesystem modules at module initialization time.
HealthCheckError
- Throw this error within custom indicators to signal a "down" state.
Related Packages
@fluojs/metrics: Often used together for observability.@fluojs/prisma/@fluojs/drizzle/@fluojs/redis: Peer dependencies for specific indicators.
Example Sources
examples/ops-metrics-terminus/src/app.ts: End-to-end integration of health and metrics.packages/terminus/src/health-check.test.ts: Demonstrates aggregation and assertion flow.
