mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:50:43 +00:00
fix(feishu): make card action retries explicit
This commit is contained in:
@@ -2,6 +2,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { createRuntimeEnv } from "../../../test/helpers/plugins/runtime-env.js";
|
||||
import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js";
|
||||
import {
|
||||
FeishuRetryableCardActionError,
|
||||
handleFeishuCardAction,
|
||||
resetProcessedFeishuCardActionTokensForTests,
|
||||
type FeishuCardActionEvent,
|
||||
@@ -88,6 +89,9 @@ describe("Feishu Card Action Handler", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.mocked(handleFeishuMessage)
|
||||
.mockReset()
|
||||
.mockResolvedValue(undefined as never);
|
||||
resetProcessedFeishuCardActionTokensForTests();
|
||||
});
|
||||
|
||||
@@ -363,7 +367,7 @@ describe("Feishu Card Action Handler", () => {
|
||||
expect(handleFeishuMessage).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("releases a claimed token when dispatch fails so retries can succeed", async () => {
|
||||
it("keeps a claimed token completed after a non-retryable dispatch failure", async () => {
|
||||
const event = createStructuredQuickActionEvent({
|
||||
token: "tok11",
|
||||
action: "feishu.quick_actions.help",
|
||||
@@ -376,6 +380,22 @@ describe("Feishu Card Action Handler", () => {
|
||||
await expect(handleFeishuCardAction({ cfg, event, runtime })).rejects.toThrow("transient");
|
||||
await handleFeishuCardAction({ cfg, event, runtime });
|
||||
|
||||
expect(handleFeishuMessage).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("releases a claimed token for explicit retryable dispatch failures", async () => {
|
||||
const event = createStructuredQuickActionEvent({
|
||||
token: "tok11-retryable",
|
||||
action: "feishu.quick_actions.help",
|
||||
command: "/help",
|
||||
});
|
||||
vi.mocked(handleFeishuMessage)
|
||||
.mockRejectedValueOnce(new FeishuRetryableCardActionError("retry me"))
|
||||
.mockResolvedValueOnce(undefined as never);
|
||||
|
||||
await expect(handleFeishuCardAction({ cfg, event, runtime })).rejects.toThrow("retry me");
|
||||
await handleFeishuCardAction({ cfg, event, runtime });
|
||||
|
||||
expect(handleFeishuMessage).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
|
||||
@@ -35,6 +35,13 @@ const processedCardActionTokens = new Map<
|
||||
{ status: "inflight" | "completed"; expiresAt: number }
|
||||
>();
|
||||
|
||||
export class FeishuRetryableCardActionError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
this.name = "FeishuRetryableCardActionError";
|
||||
}
|
||||
}
|
||||
|
||||
export function resetProcessedFeishuCardActionTokensForTests(): void {
|
||||
processedCardActionTokens.clear();
|
||||
}
|
||||
@@ -304,7 +311,11 @@ export async function handleFeishuCardAction(params: {
|
||||
});
|
||||
completeFeishuCardActionToken({ token: event.token, accountId: account.accountId });
|
||||
} catch (err) {
|
||||
releaseFeishuCardActionToken({ token: event.token, accountId: account.accountId });
|
||||
if (err instanceof FeishuRetryableCardActionError) {
|
||||
releaseFeishuCardActionToken({ token: event.token, accountId: account.accountId });
|
||||
} else {
|
||||
completeFeishuCardActionToken({ token: event.token, accountId: account.accountId });
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user