feat: add per-project message trigger wait queue

- TriggerQueue: FIFO per-project queue, max 5 items, 5min TTL expiry
- Replace reject-when-locked with queue: users get position feedback
- Run completion auto-starts next queued trigger (skips expired items)
- /reset clears project queue; 60s periodic purge interval
- Add unit tests (10) for queue lifecycle and edge cases
This commit is contained in:
2026-07-08 17:31:43 +08:00
parent 4479f88f4f
commit 36c0801e6f
5 changed files with 442 additions and 16 deletions
+8
View File
@@ -16,6 +16,7 @@ import { prisma } from "./db.js";
import { createEnvRuntimeSettings } from "./settings/runtime.js";
import { createLarkClient, startFeishuListenerWithClient } from "./feishu/client.js";
import { makeTriggerHandler } from "./feishu/trigger.js";
import { triggerQueue } from "./feishu/triggerQueue.js";
function requireEnv(name: string): string {
const v = process.env[name];
@@ -61,6 +62,13 @@ async function main(): Promise<void> {
if (feishuListenerEnabled) {
const feishuConfig = { appId: feishuAppId, appSecret: feishuAppSecret, botOpenId: feishuBotOpenId };
const larkClient = createLarkClient(feishuConfig);
const triggerQueuePurgeTimer = setInterval(() => {
const removed = triggerQueue.purgeExpired();
if (removed > 0) {
app.log.info({ removed }, "feishu trigger queue: purged expired triggers");
}
}, 60_000);
triggerQueuePurgeTimer.unref();
const trigger = makeTriggerHandler({ prisma, settings: runtimeSettings, logger: app.log });
startFeishuListenerWithClient(feishuConfig, larkClient, app.log, trigger, trigger.onCardAction);
} else {