diff --git a/extensions/telegram/src/send.test.ts b/extensions/telegram/src/send.test.ts index 78bc68c47140..3425b450737c 100644 --- a/extensions/telegram/src/send.test.ts +++ b/extensions/telegram/src/send.test.ts @@ -368,7 +368,24 @@ describe("sent-message-cache", () => { expect(wasSentByBot(123, 1)).toBe(true); }); - it("persists sent-message rows with their remaining logical ttl", () => { + it("persists only the newly recorded sent-message row", () => { + const persistedMessageIds: string[] = []; + setTelegramSentMessageStoreForTest({ + ...sentMessageStore, + register(key, value, options) { + sentMessageStore.register(key, value, options); + persistedMessageIds.push(value.messageId); + }, + }); + + recordSentMessage(123, 1); + recordSentMessage(123, 2); + recordSentMessage(456, 10); + + expect(persistedMessageIds).toEqual(["1", "2", "10"]); + }); + + it("persists sent-message rows with a per-entry ttl", () => { vi.useFakeTimers(); vi.setSystemTime(new Date("2026-01-26T12:00:00.000Z")); const ttlByMessageId = new Map(); @@ -384,7 +401,7 @@ describe("sent-message-cache", () => { vi.advanceTimersByTime(60 * 60 * 1000); recordSentMessage(123, 2); - expect(ttlByMessageId.get("1")).toBe(23 * 60 * 60 * 1000); + expect(ttlByMessageId.get("1")).toBe(24 * 60 * 60 * 1000); expect(ttlByMessageId.get("2")).toBe(24 * 60 * 60 * 1000); }); diff --git a/extensions/telegram/src/sent-message-cache.ts b/extensions/telegram/src/sent-message-cache.ts index 2a4db1ccb9d9..5a1244bf7fdc 100644 --- a/extensions/telegram/src/sent-message-cache.ts +++ b/extensions/telegram/src/sent-message-cache.ts @@ -105,6 +105,12 @@ function cleanupExpired( } } +function cleanupExpiredSentMessages(store: SentMessageStore, now: number): void { + for (const [scopeKey, entry] of store) { + cleanupExpired(store, scopeKey, entry, now); + } +} + function readLegacySentMessages(filePath: string): SentMessageStore { try { const raw = fs.readFileSync(filePath, "utf-8"); @@ -173,23 +179,17 @@ function getSentMessages(cfg?: Pick): SentMessageStor return getSentMessageBucket(cfg).store; } -function persistSentMessages(bucket: SentMessageBucket): void { - const { store, scopeKey } = bucket; - const now = Date.now(); - for (const [chatId, entry] of store) { - cleanupExpired(store, chatId, entry, now); - for (const [messageId, timestamp] of entry) { - const ttlMs = TTL_MS - Math.max(0, now - timestamp); - if (ttlMs <= 0) { - continue; - } - openSentMessageStore().register( - sentMessageEntryKey(scopeKey, chatId, messageId), - { scopeKey, chatId, messageId, timestamp }, - { ttlMs }, - ); - } - } +function persistSentMessage( + bucket: SentMessageBucket, + chatId: string, + messageId: string, + timestamp: number, +): void { + openSentMessageStore().register( + sentMessageEntryKey(bucket.scopeKey, chatId, messageId), + { scopeKey: bucket.scopeKey, chatId, messageId, timestamp }, + { ttlMs: TTL_MS }, + ); } export function recordSentMessage( @@ -208,11 +208,9 @@ export function recordSentMessage( store.set(scopeKey, entry); } entry.set(idKey, now); - if (entry.size > 100) { - cleanupExpired(store, scopeKey, entry, now); - } + cleanupExpiredSentMessages(store, now); try { - persistSentMessages(bucket); + persistSentMessage(bucket, scopeKey, idKey, now); } catch (error) { logVerbose(`telegram: failed to persist sent-message cache: ${String(error)}`); }