Saltar al contenido principal

Implementing a new probe strategy

All probe strategies live in apps/backend/src/status/application/services/probes/.

Interface

export interface ProbeStrategy {
readonly probeType: string; // must match status_probe_type enum value
run(config: Record<string, unknown>): Promise<ProbeResult>;
}

export interface ProbeResult {
status: StatusLevel;
latencyMs: number;
error?: string;
}

Steps

  1. Create my-probe.probe.ts in probes/ implementing ProbeStrategy.
  2. Decorate with @Injectable().
  3. Enforce a 5s timeout and capture latencyMs.
  4. Return { status, latencyMs, error? } — never throw (catch internally).
  5. Add the class to StatusModule providers under probeStrategies.
  6. Call probeRunner.register([..., myProbe]) in StatusModule.onModuleInit().
  7. Add the probe_type string value to the status_probe_type DB enum via a migration.
  8. Re-run pnpm run generate:types.

Example (minimal http probe)

import type { ProbeResult, ProbeStrategy } from "./probe-strategy.interface";
import { Injectable } from "@nestjs/common";

const TIMEOUT_MS = 5_000;

@Injectable()
export class MyProbe implements ProbeStrategy {
readonly probeType = "my_probe";

async run(config: Record<string, unknown>): Promise<ProbeResult> {
const start = Date.now();
try {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
const res = await fetch(config.url as string, { signal: controller.signal })
.finally(() => clearTimeout(timer));
return { status: res.ok ? "operational" : "degraded_performance", latencyMs: Date.now() - start };
} catch (err) {
return { status: "major_outage", latencyMs: Date.now() - start, error: String(err) };
}
}
}

Config schema

Document the expected config fields in a JSDoc on run(). Example:

/**
* @param config.url - Full URL to fetch
* @param config.expectedStatus - Expected HTTP status (default 200)
*/

Timeout enforcement

Every probe must enforce a timeout. Use Promise.race with a reject timer or AbortController. A slow external service must never block the probe cycle — health-probe.processor.ts runs probes concurrently but a stuck promise would leak memory.