From a5762e19cf08ecb695edc75dff218f0c06cf69b7 Mon Sep 17 00:00:00 2001 From: m4air Date: Sat, 19 Sep 2026 16:22:22 -0700 Subject: [PATCH] fix(memory): bound automation dispatch tokens --- src/main/automations/dispatch-tokens.test.ts | 16 ++++++++++++++++ src/main/automations/dispatch-tokens.ts | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/main/automations/dispatch-tokens.test.ts diff --git a/src/main/automations/dispatch-tokens.test.ts b/src/main/automations/dispatch-tokens.test.ts new file mode 100644 index 00000000000..4898f75fe4d --- /dev/null +++ b/src/main/automations/dispatch-tokens.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from 'vitest' +import { + createAutomationDispatchToken, + getAutomationDispatchTokenCountForTests, + MAX_AUTOMATION_DISPATCH_TOKENS +} from './dispatch-tokens' + +describe('automation dispatch tokens', () => { + it('bounds distinct token churn', () => { + for (let index = 0; index < MAX_AUTOMATION_DISPATCH_TOKENS + 4; index += 1) { + createAutomationDispatchToken(`automation-${index}`, `run-${index}`) + } + + expect(getAutomationDispatchTokenCountForTests()).toBe(MAX_AUTOMATION_DISPATCH_TOKENS) + }) +}) diff --git a/src/main/automations/dispatch-tokens.ts b/src/main/automations/dispatch-tokens.ts index b8856a16220..ce623d65d7d 100644 --- a/src/main/automations/dispatch-tokens.ts +++ b/src/main/automations/dispatch-tokens.ts @@ -1,6 +1,7 @@ import { randomUUID } from 'node:crypto' const DISPATCH_TOKEN_TTL_MS = 30 * 60_000 +export const MAX_AUTOMATION_DISPATCH_TOKENS = 1024 type DispatchTokenRecord = { automationId: string @@ -20,6 +21,16 @@ function pruneExpiredDispatchTokens(now = Date.now()): void { } } +function trimDispatchTokens(): void { + while (dispatchTokens.size > MAX_AUTOMATION_DISPATCH_TOKENS) { + const oldestEvictable = [...dispatchTokens].find(([, record]) => !record.inFlight) + if (!oldestEvictable) { + return + } + dispatchTokens.delete(oldestEvictable[0]) + } +} + export function createAutomationDispatchToken(automationId: string, runId: string): string { pruneExpiredDispatchTokens() const token = randomUUID() @@ -29,9 +40,14 @@ export function createAutomationDispatchToken(automationId: string, runId: strin expiresAt: Date.now() + DISPATCH_TOKEN_TTL_MS, inFlight: false }) + trimDispatchTokens() return token } +export function getAutomationDispatchTokenCountForTests(): number { + return dispatchTokens.size +} + export function beginAutomationDispatchTokenUse(args: { automationId: string runId: string