Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
4.1 kB · 133 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134/** * Session activity tracking with refcount-based heartbeat timer. * * The transport registers its keep-alive sender via registerSessionActivityCallback(). * Callers (API streaming, tool execution) bracket their work with * startSessionActivity() / stopSessionActivity(). When the refcount is >0 a * periodic timer fires the registered callback every 30 seconds to keep the * container alive. * * Sending keep-alives is gated behind CLAUDE_CODE_REMOTE_SEND_KEEPALIVES. * Diagnostic logging always fires to help diagnose idle gaps. */
import { registerCleanup } from './cleanupRegistry.js'import { logForDiagnosticsNoPII } from './diagLogs.js'import { isEnvTruthy } from './envUtils.js'
const SESSION_ACTIVITY_INTERVAL_MS = 30_000
export type SessionActivityReason = 'api_call' | 'tool_exec'
let activityCallback: (() => void) | null = nulllet refcount = 0const activeReasons = new Map<SessionActivityReason, number>()let oldestActivityStartedAt: number | null = nulllet heartbeatTimer: ReturnType<typeof setInterval> | null = nulllet idleTimer: ReturnType<typeof setTimeout> | null = nulllet cleanupRegistered = false
function startHeartbeatTimer(): void { clearIdleTimer() heartbeatTimer = setInterval(() => { logForDiagnosticsNoPII('debug', 'session_keepalive_heartbeat', { refcount, }) if (isEnvTruthy(process.env.CLAUDE_CODE_REMOTE_SEND_KEEPALIVES)) { activityCallback?.() } }, SESSION_ACTIVITY_INTERVAL_MS)}
function startIdleTimer(): void { clearIdleTimer() if (activityCallback === null) { return } idleTimer = setTimeout(() => { logForDiagnosticsNoPII('info', 'session_idle_30s') idleTimer = null }, SESSION_ACTIVITY_INTERVAL_MS)}
function clearIdleTimer(): void { if (idleTimer !== null) { clearTimeout(idleTimer) idleTimer = null }}
export function registerSessionActivityCallback(cb: () => void): void { activityCallback = cb // Restart timer if work is already in progress (e.g. reconnect during streaming) if (refcount > 0 && heartbeatTimer === null) { startHeartbeatTimer() }}
export function unregisterSessionActivityCallback(): void { activityCallback = null // Stop timer if the callback is removed if (heartbeatTimer !== null) { clearInterval(heartbeatTimer) heartbeatTimer = null } clearIdleTimer()}
export function sendSessionActivitySignal(): void { if (isEnvTruthy(process.env.CLAUDE_CODE_REMOTE_SEND_KEEPALIVES)) { activityCallback?.() }}
export function isSessionActivityTrackingActive(): boolean { return activityCallback !== null}
/** * Increment the activity refcount. When it transitions from 0→1 and a callback * is registered, start a periodic heartbeat timer. */export function startSessionActivity(reason: SessionActivityReason): void { refcount++ activeReasons.set(reason, (activeReasons.get(reason) ?? 0) + 1) if (refcount === 1) { oldestActivityStartedAt = Date.now() if (activityCallback !== null && heartbeatTimer === null) { startHeartbeatTimer() } } if (!cleanupRegistered) { cleanupRegistered = true registerCleanup(async () => { logForDiagnosticsNoPII('info', 'session_activity_at_shutdown', { refcount, active: Object.fromEntries(activeReasons), // Only meaningful while work is in-flight; stale otherwise. oldest_activity_ms: refcount > 0 && oldestActivityStartedAt !== null ? Date.now() - oldestActivityStartedAt : null, }) }) }}
/** * Decrement the activity refcount. When it reaches 0, stop the heartbeat timer * and start an idle timer that logs after 30s of inactivity. */export function stopSessionActivity(reason: SessionActivityReason): void { if (refcount > 0) { refcount-- } const n = (activeReasons.get(reason) ?? 0) - 1 if (n > 0) activeReasons.set(reason, n) else activeReasons.delete(reason) if (refcount === 0 && heartbeatTimer !== null) { clearInterval(heartbeatTimer) heartbeatTimer = null startIdleTimer() }}