import { EventEmitter } from "node:events"; import { Transport } from "./transport.js"; import { Cluster } from "./cluster.js"; /** * Configuration for the heartbeat protocol. */ export interface HeartbeatConfig { /** Enable/disable heartbeat protocol. Default: true */ enabled: boolean; /** How often to run the heartbeat loop (ms). Default: 1000 */ intervalMs: number; /** Timeout waiting for pong response (ms). Default: 2000 */ timeoutMs: number; /** Number of missed heartbeats before declaring node dead. Default: 3 */ maxMissedHeartbeats: number; /** Stagger pings across interval to avoid network bursts. Default: true */ staggerPings: boolean; } /** * Default heartbeat configuration. */ export declare const DEFAULT_HEARTBEAT_CONFIG: HeartbeatConfig; /** * RPC message for heartbeat ping. */ export interface HeartbeatPing { type: "heartbeat:ping"; timestamp: number; senderId: string; } /** * RPC message for heartbeat pong response. */ export interface HeartbeatPong { type: "heartbeat:pong"; timestamp: number; responderId: string; } /** * Tracks heartbeat state for a single peer. */ interface PeerHeartbeatState { nodeId: string; missedCount: number; lastPongTime: number; pendingPing: boolean; isLeaving: boolean; } /** * HeartbeatManager provides active failure detection via ping/pong messages. * * It complements the passive gossip-based failure detection by actively * probing peers over the RPC transport layer, enabling faster detection * of node failures. * * Events: * - 'node_failed': Emitted when a node is detected as failed (missed too many heartbeats) * * @example * ```typescript * const heartbeat = new HeartbeatManager(nodeId, transport, cluster, config); * heartbeat.on('node_failed', (nodeId) => { * console.log(`Node ${nodeId} failed`); * system.handleNodeFailure(nodeId); * }); * await heartbeat.start(); * ``` */ export declare class HeartbeatManager extends EventEmitter { private readonly nodeId; private readonly transport; private readonly cluster; private readonly config; private readonly log; private readonly peerStates; private heartbeatTimer?; private staggerTimers; private _isRunning; private readonly boundHandleMemberJoin; private readonly boundHandleMemberLeave; constructor(nodeId: string, transport: Transport, cluster: Cluster, config?: Partial); /** * Returns whether the heartbeat manager is currently running. */ isRunning(): boolean; /** * Starts the heartbeat manager. * Begins periodic ping/pong exchanges with all known peers. */ start(): Promise; /** * Stops the heartbeat manager. * Cancels all pending pings and timers. */ stop(): Promise; /** * Handles a heartbeat ping request and returns a pong response. * This should be called by the ActorSystem's RPC handler. */ handlePing(ping: HeartbeatPing): HeartbeatPong; /** * Initialize peer states from current cluster members. */ private initializePeerStates; /** * Add a peer to heartbeat tracking. */ private addPeer; /** * Remove a peer from heartbeat tracking. */ private removePeer; /** * Handle cluster member join event. * Event may emit either a string nodeId or an object with { id: string }. */ private handleMemberJoin; /** * Handle cluster member leave event. * Event may emit either a string nodeId or an object with { id: string, status?: string }. */ private handleMemberLeave; /** * Main heartbeat loop - sends pings to all peers. */ private heartbeatLoop; /** * Send a ping to a single peer and handle the response. */ private pingPeer; /** * Get the current heartbeat state for a peer (for testing/debugging). */ getPeerState(nodeId: string): PeerHeartbeatState | undefined; /** * Get all tracked peer node IDs (for testing/debugging). */ getTrackedPeers(): string[]; } export {}; //# sourceMappingURL=heartbeat.d.ts.map