Files
skills/docs/api-stack/api/api-2pc/src/limits/timeout-ceiling.md
2026-05-29 08:20:56 +01:00

2.6 KiB

limits/timeout-ceiling

Purpose

Enforces the hard 30 000 ms ceiling on caller-supplied timeoutMs values. The check fires at the public entry point of run2pc so above-ceiling calls never contact a participant; the operational warning in design doc §9.2 is that long prepares hold row-level locks, so surfacing the misuse loudly is more useful than silently clamping.

This module is intentionally tiny — one function — because the behaviour is small but the gate is one of the most-asserted contracts in the spec.

Features

  • assertTimeoutBelowCeiling(timeoutMs) — throws TWOPC_TIMEOUT_CEILING_EXCEEDED for above-ceiling, non-positive, non-finite, or NaN inputs.
  • Re-uses the TIMEOUT_CEILING_MS constant from options/ so the ceiling stays a single source of truth.

Usage: Basic

import { assertTimeoutBelowCeiling } from "@suaveplan/api-2pc/limits";

assertTimeoutBelowCeiling(5000); // ok
assertTimeoutBelowCeiling(30001); // throws TWOPC_TIMEOUT_CEILING_EXCEEDED

Usage: Advanced

The function is intentionally side-effect-free so callers can wrap it in a per-tenant override path:

import { TIMEOUT_CEILING_MS } from "@suaveplan/api-2pc/options";
import { assertTimeoutBelowCeiling } from "@suaveplan/api-2pc/limits";

function resolveTimeout(
    requested: number | undefined,
    tenantMax: number
): number {
    const effective = requested ?? DEFAULT_TIMEOUT_MS;
    assertTimeoutBelowCeiling(effective);
    if (effective > tenantMax) {
        return tenantMax;
    }
    if (effective > TIMEOUT_CEILING_MS) {
        // unreachable given the assert above — included only to
        // illustrate that the ceiling acts as the strict upper bound.
        return TIMEOUT_CEILING_MS;
    }
    return effective;
}

API Reference

  • function assertTimeoutBelowCeiling(timeoutMs: number): void
    • Throws TwoPcError(TWOPC_CODES.TIMEOUT_CEILING_EXCEEDED) for any of: NaN, Infinity, -Infinity, values <= 0, values > TIMEOUT_CEILING_MS.

Implementation Notes

The check rejects non-positive values for the same reason it rejects above-ceiling ones: an immediate or backwards-in-time deadline would collapse phase 1 to a single tick and the rollback path would fire before any participant could finish a real prepare. Treating that as the same misuse class as "30 minutes" is a deliberate ergonomic choice — operators get one error code to grep for.

Number.isFinite is used in preference to Number.isNaN because the former covers Infinity and -Infinity in addition to NaN. The explicit <= 0 check then excludes zero and negative-finite values.