mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 19:00:45 +00:00
fix(feishu): make bot menu retries explicit
This commit is contained in:
@@ -37,6 +37,25 @@ import type { FeishuChatType, ResolvedFeishuAccount } from "./types.js";
|
||||
|
||||
const FEISHU_REACTION_VERIFY_TIMEOUT_MS = 1_500;
|
||||
|
||||
export class FeishuRetryableSyntheticEventError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
this.name = "FeishuRetryableSyntheticEventError";
|
||||
}
|
||||
}
|
||||
|
||||
function isFeishuRetryableSyntheticEventError(
|
||||
error: unknown,
|
||||
): error is FeishuRetryableSyntheticEventError {
|
||||
return (
|
||||
error instanceof FeishuRetryableSyntheticEventError ||
|
||||
(typeof error === "object" &&
|
||||
error !== null &&
|
||||
"name" in error &&
|
||||
error.name === "FeishuRetryableSyntheticEventError")
|
||||
);
|
||||
}
|
||||
|
||||
export type FeishuReactionCreatedEvent = {
|
||||
message_id: string;
|
||||
chat_id?: string;
|
||||
@@ -781,8 +800,12 @@ function registerEventHandlers(
|
||||
}
|
||||
return await handleLegacyMenu();
|
||||
})
|
||||
.catch((err) => {
|
||||
releaseFeishuMessageProcessing(syntheticMessageId, accountId);
|
||||
.catch(async (err) => {
|
||||
if (isFeishuRetryableSyntheticEventError(err)) {
|
||||
releaseFeishuMessageProcessing(syntheticMessageId, accountId);
|
||||
} else {
|
||||
await recordProcessedFeishuMessage(syntheticMessageId, accountId, log);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
if (fireAndForget) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
createResolvedFeishuLifecycleAccount,
|
||||
expectFeishuReplyDispatcherSentFinalReplyOnce,
|
||||
expectFeishuReplyPipelineDedupedAcrossReplay,
|
||||
expectFeishuReplyPipelineDedupedAfterPostSendFailure,
|
||||
expectFeishuSingleEffectAcrossReplay,
|
||||
installFeishuLifecycleReplyRuntime,
|
||||
mockFeishuReplyOnceDispatch,
|
||||
@@ -189,4 +190,29 @@ describe("Feishu bot-menu lifecycle", () => {
|
||||
|
||||
expectFeishuReplyDispatcherSentFinalReplyOnce({ createFeishuReplyDispatcherMock });
|
||||
});
|
||||
|
||||
it("does not duplicate delivery when launcher fallback hits a post-send failure", async () => {
|
||||
const onBotMenu = await setupLifecycleMonitor();
|
||||
const event = createBotMenuEvent({
|
||||
eventKey: "quick-actions",
|
||||
timestamp: "1700000000002",
|
||||
});
|
||||
sendCardFeishuMock.mockRejectedValueOnce(new Error("boom"));
|
||||
dispatchReplyFromConfigMock.mockImplementationOnce(async ({ dispatcher }) => {
|
||||
await dispatcher.sendFinalReply({ text: "menu reply once" });
|
||||
throw new Error("post-send failure");
|
||||
});
|
||||
|
||||
await expectFeishuReplyPipelineDedupedAfterPostSendFailure({
|
||||
handler: onBotMenu,
|
||||
event,
|
||||
dispatchReplyFromConfigMock,
|
||||
runtimeErrorMock: lastRuntime?.error as ReturnType<typeof vi.fn>,
|
||||
waitTimeoutMs: 5_000,
|
||||
});
|
||||
|
||||
expect(sendCardFeishuMock).toHaveBeenCalledTimes(1);
|
||||
expect(dispatchReplyFromConfigMock).toHaveBeenCalledTimes(1);
|
||||
expectFeishuReplyDispatcherSentFinalReplyOnce({ createFeishuReplyDispatcherMock });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -231,4 +231,28 @@ describe("Feishu bot menu handler", () => {
|
||||
expect(sentCard?.config?.wide_screen_mode).toBeUndefined();
|
||||
expect(sentCard?.config?.enable_forward).toBeUndefined();
|
||||
});
|
||||
|
||||
it("reopens replay for explicit retryable fallback failures", async () => {
|
||||
const onBotMenu = await registerHandlers();
|
||||
sendCardFeishuMock
|
||||
.mockImplementationOnce(async () => {
|
||||
throw new Error("boom");
|
||||
})
|
||||
.mockImplementationOnce(async () => {
|
||||
throw new Error("boom");
|
||||
});
|
||||
handleFeishuMessageMock
|
||||
.mockRejectedValueOnce(
|
||||
Object.assign(new Error("retry me"), {
|
||||
name: "FeishuRetryableSyntheticEventError",
|
||||
}),
|
||||
)
|
||||
.mockResolvedValueOnce(undefined);
|
||||
|
||||
await onBotMenu(createBotMenuEvent({ eventKey: "quick-actions", timestamp: "1700000000004" }));
|
||||
await onBotMenu(createBotMenuEvent({ eventKey: "quick-actions", timestamp: "1700000000004" }));
|
||||
|
||||
expect(sendCardFeishuMock).toHaveBeenCalledTimes(2);
|
||||
expect(handleFeishuMessageMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user