* Creates a stall watchdog that aborts the attempt when no events arrive * within the configured timeout. Call start() only after the subscription * connection is established so handshake latency isn't misclassified as * stream silence.
(
attemptController: AbortController,
label: string
)
| 3017 | * stream silence. |
| 3018 | */ |
| 3019 | private createStallWatchdog( |
| 3020 | attemptController: AbortController, |
| 3021 | label: string |
| 3022 | ): { markEvent: () => void; start: () => void; stop: () => void } { |
| 3023 | let lastEventAt = Date.now(); |
| 3024 | let interval: ReturnType<typeof setInterval> | null = null; |
| 3025 | |
| 3026 | return { |
| 3027 | markEvent: () => { |
| 3028 | lastEventAt = Date.now(); |
| 3029 | }, |
| 3030 | start: () => { |
| 3031 | if (interval != null) { |
| 3032 | return; |
| 3033 | } |
| 3034 | |
| 3035 | lastEventAt = Date.now(); |
| 3036 | interval = setInterval(() => { |
| 3037 | if (attemptController.signal.aborted) { |
| 3038 | return; |
| 3039 | } |
| 3040 | |
| 3041 | const elapsedMs = Date.now() - lastEventAt; |
| 3042 | if (elapsedMs < SUBSCRIPTION_STALL_TIMEOUT_MS) { |
| 3043 | return; |
| 3044 | } |
| 3045 | |
| 3046 | console.warn( |
| 3047 | `[WorkspaceStore] ${label} stalled (no events for ${elapsedMs}ms); retrying...` |
| 3048 | ); |
| 3049 | attemptController.abort(); |
| 3050 | }, SUBSCRIPTION_STALL_CHECK_INTERVAL_MS); |
| 3051 | }, |
| 3052 | stop: () => { |
| 3053 | if (interval != null) { |
| 3054 | clearInterval(interval); |
| 3055 | interval = null; |
| 3056 | } |
| 3057 | }, |
| 3058 | }; |
| 3059 | } |
| 3060 | |
| 3061 | private async runTerminalActivitySubscription(controller: AbortController): Promise<void> { |
| 3062 | const signal = controller.signal; |
no test coverage detected