From 75b79f6f59e919657e0da70094fa6843e10937a0 Mon Sep 17 00:00:00 2001 From: teconomix Date: Fri, 20 Mar 2026 11:39:22 +0000 Subject: [PATCH] fix(mattermost): use patchInflight in flushPendingPatch and divergent-target wait flushPendingPatch and the divergent-target branch were still using a 2-second busy-wait on patchSending, which has the same race as the onSettled wait that was already fixed: patchSending clears in the finally block before the network request actually settles. Both paths now await patchInflight directly. (ID=2965256849) --- .../mattermost/src/mattermost/monitor.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/extensions/mattermost/src/mattermost/monitor.ts b/extensions/mattermost/src/mattermost/monitor.ts index 20d3552bb05..44bb6bce94e 100644 --- a/extensions/mattermost/src/mattermost/monitor.ts +++ b/extensions/mattermost/src/mattermost/monitor.ts @@ -1436,14 +1436,11 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {} const flushPendingPatch = async () => { stopPatchInterval(); if (!blockStreamingClient) return; - // Wait for any in-flight interval tick to settle before flushing. - // Without this, an interval tick that set lastSentText synchronously but hasn't - // completed the async send yet would cause flushPendingPatch to exit early - // (text === lastSentText guard), leaving streamMessageId null and causing - // final delivery to fall through to a new post instead of patching in place. - const deadline = Date.now() + 2000; - while (patchSending && Date.now() < deadline) { - await new Promise((r) => setTimeout(r, 20)); + // Await the in-flight promise directly so we never miss a late-resolving + // POST/PATCH — the busy-wait on patchSending had a race where patchSending + // could clear before the network request settled (ID=2965256849). + if (patchInflight) { + await patchInflight.catch(() => {}); } const rawText = pendingPatchText; if (!rawText) return; @@ -1567,9 +1564,8 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {} // first sendMessageMattermost resolves during this window, so the orphan // cleanup below can capture and delete it. stopPatchInterval(); - const deadline = Date.now() + 2000; - while (patchSending && Date.now() < deadline) { - await new Promise((r) => setTimeout(r, 20)); + if (patchInflight) { + await patchInflight.catch(() => {}); } } else { // Same thread: flush pending patches normally.