




















@@ -33,6 +33,18 @@ type SlackQaRuntimeEnv = {
3333sutAppToken: string;
3434};
353536+type SlackChannelStatus = {
37+connected?: boolean;
38+lastConnectedAt?: number;
39+lastDisconnect?: unknown;
40+lastError?: string;
41+restartPending?: boolean;
42+running?: boolean;
43+};
44+45+const SLACK_QA_READY_TIMEOUT_MS = 45_000;
46+const SLACK_QA_READY_STABILITY_MS = 3_000;
47+3648type SlackQaScenarioId =
3749| "slack-allowlist-block"
3850| "slack-canary"
@@ -711,19 +723,10 @@ async function waitForSlackNoReply(params: {
711723async function waitForSlackChannelRunning(
712724gateway: Awaited<ReturnType<typeof startQaGatewayChild>>,
713725accountId: string,
714-) {
726+): Promise<SlackChannelStatus> {
715727const startedAt = Date.now();
716-let lastStatus:
717-| {
718-connected?: boolean;
719-lastConnectedAt?: number;
720-lastDisconnect?: unknown;
721-lastError?: string;
722-restartPending?: boolean;
723-running?: boolean;
724-}
725-| undefined;
726-while (Date.now() - startedAt < 45_000) {
728+let lastStatus: SlackChannelStatus | undefined;
729+while (Date.now() - startedAt < SLACK_QA_READY_TIMEOUT_MS) {
727730try {
728731const payload = (await gateway.call(
729732"channels.status",
@@ -756,7 +759,10 @@ async function waitForSlackChannelRunning(
756759}
757760 : undefined;
758761if (match?.running && match.connected === true && match.restartPending !== true) {
759-return;
762+if (!lastStatus) {
763+throw new Error(`slack account "${accountId}" status disappeared after readiness check`);
764+}
765+return lastStatus;
760766}
761767} catch {
762768// retry
@@ -769,6 +775,30 @@ async function waitForSlackChannelRunning(
769775);
770776}
771777778+async function waitForSlackChannelStable(
779+gateway: Awaited<ReturnType<typeof startQaGatewayChild>>,
780+accountId: string,
781+) {
782+const startedAt = Date.now();
783+while (Date.now() - startedAt < SLACK_QA_READY_TIMEOUT_MS) {
784+const status = await waitForSlackChannelRunning(gateway, accountId);
785+const connectedAt =
786+typeof status.lastConnectedAt === "number" && status.lastConnectedAt > 0
787+ ? status.lastConnectedAt
788+ : Date.now();
789+const connectedForMs = Date.now() - connectedAt;
790+if (connectedForMs >= SLACK_QA_READY_STABILITY_MS) {
791+return;
792+}
793+await new Promise((resolve) =>
794+setTimeout(resolve, Math.max(500, SLACK_QA_READY_STABILITY_MS - connectedForMs)),
795+);
796+}
797+throw new Error(
798+`slack account "${accountId}" did not remain ready for ${SLACK_QA_READY_STABILITY_MS}ms`,
799+);
800+}
801+772802function toObservedSlackArtifacts(params: {
773803includeContent: boolean;
774804messages: SlackObservedMessage[];
@@ -923,7 +953,7 @@ export async function runSlackQaLive(params: {
923953}),
924954});
925955const activeGatewayHarness = gatewayHarness;
926-await waitForSlackChannelRunning(activeGatewayHarness.gateway, sutAccountId);
956+await waitForSlackChannelStable(activeGatewayHarness.gateway, sutAccountId);
927957const scenarioRun = scenario.buildRun(sutIdentity.userId);
928958const baseScenarioContext = {
929959channelId: activeRuntimeEnv.channelId,
@@ -939,7 +969,7 @@ export async function runSlackQaLive(params: {
939969 sutIdentity,
940970 sutReadClient,
941971waitForReady: async () =>
942-await waitForSlackChannelRunning(activeGatewayHarness.gateway, sutAccountId),
972+await waitForSlackChannelStable(activeGatewayHarness.gateway, sutAccountId),
943973};
944974const beforeRunResult = await scenarioRun.beforeRun?.(baseScenarioContext);
945975const beforeRunDetails =
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。