
























@@ -975,6 +975,121 @@ describe("TelegramPollingSession", () => {
975975});
976976});
977977978+it("dead-letters missing harness failures so later same-lane updates can drain", async () => {
979+await withTempSpool(async (tempDir) => {
980+const abort = new AbortController();
981+const log = vi.fn();
982+const events: string[] = [];
983+await writeSpooledTestUpdates(tempDir, [
984+topicUpdate(42, 10, "missing harness turn"),
985+topicUpdate(43, 11, "other topic turn"),
986+topicUpdate(44, 10, "same topic after missing harness"),
987+]);
988+989+const { runPromise, stopWorker } = startIsolatedIngressSession({
990+ abort,
991+spoolDir: tempDir,
992+ log,
993+drainIntervalMs: 10,
994+handleUpdate: async (update) => {
995+if (update.update_id === 42) {
996+events.push("topic10:first");
997+const err = new Error(
998+'Requested agent harness "missing-harness-85470" is not registered.',
999+);
1000+err.name = "MissingAgentHarnessError";
1001+throw err;
1002+}
1003+if (update.update_id === 43) {
1004+events.push("topic11");
1005+return;
1006+}
1007+if (update.update_id === 44) {
1008+events.push("topic10:second");
1009+abort.abort();
1010+}
1011+},
1012+});
1013+1014+await vi.waitFor(() =>
1015+expect(events).toEqual(["topic10:first", "topic11", "topic10:second"]),
1016+);
1017+await vi.waitFor(async () => expect(await pendingUpdateIds(tempDir, "all")).toEqual([]));
1018+expect(await failedUpdateIds(tempDir)).toEqual([42]);
1019+expectLogIncludes(log, "spooled update 42 failed with non-retryable missing-agent-harness");
1020+expectLogIncludes(log, "dead-lettered");
1021+expectLogExcludes(log, "spooled update 42 failed; keeping for retry");
1022+stopWorker();
1023+await runPromise;
1024+});
1025+});
1026+1027+it("dead-letters wrapped missing harness failures", async () => {
1028+await withTempSpool(async (tempDir) => {
1029+const abort = new AbortController();
1030+const log = vi.fn();
1031+await writeSpooledTestUpdates(tempDir, [topicUpdate(42, 10, "wrapped missing harness")]);
1032+1033+const { runPromise, stopWorker } = startIsolatedIngressSession({
1034+ abort,
1035+spoolDir: tempDir,
1036+ log,
1037+drainIntervalMs: 10,
1038+handleUpdate: async () => {
1039+const cause = new Error(
1040+'Requested agent harness "missing-harness-85470" is not registered.',
1041+);
1042+const err = new Error("Agent turn failed", { cause });
1043+throw err;
1044+},
1045+});
1046+1047+await vi.waitFor(async () => expect(await failedUpdateIds(tempDir)).toEqual([42]));
1048+expect(await pendingUpdateIds(tempDir, "all")).toEqual([]);
1049+expectLogIncludes(log, "spooled update 42 failed with non-retryable missing-agent-harness");
1050+expectLogExcludes(log, "spooled update 42 failed; keeping for retry");
1051+abort.abort();
1052+stopWorker();
1053+await runPromise;
1054+});
1055+});
1056+1057+it("dead-letters grammY BotError-wrapped missing harness failures", async () => {
1058+await withTempSpool(async (tempDir) => {
1059+const abort = new AbortController();
1060+const log = vi.fn();
1061+await writeSpooledTestUpdates(tempDir, [
1062+topicUpdate(42, 10, "bot error wrapped missing harness"),
1063+]);
1064+1065+const { runPromise, stopWorker } = startIsolatedIngressSession({
1066+ abort,
1067+spoolDir: tempDir,
1068+ log,
1069+drainIntervalMs: 10,
1070+handleUpdate: async () => {
1071+const cause = new Error(
1072+'Requested agent harness "missing-harness-85470" is not registered.',
1073+);
1074+const middlewareError = new Error("Agent turn failed", { cause });
1075+const botError = Object.assign(new Error("Error in middleware: Agent turn failed"), {
1076+name: "BotError",
1077+error: middlewareError,
1078+});
1079+throw botError;
1080+},
1081+});
1082+1083+await vi.waitFor(async () => expect(await failedUpdateIds(tempDir)).toEqual([42]));
1084+expect(await pendingUpdateIds(tempDir, "all")).toEqual([]);
1085+expectLogIncludes(log, "spooled update 42 failed with non-retryable missing-agent-harness");
1086+expectLogExcludes(log, "spooled update 42 failed; keeping for retry");
1087+abort.abort();
1088+stopWorker();
1089+await runPromise;
1090+});
1091+});
1092+9781093it("recovers restart processing claims before draining later same-lane updates", async () => {
9791094await withTempSpool(async (tempDir) => {
9801095const abort = new AbortController();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。