diff --git a/src/worker.ts b/src/worker.ts index 6aefea2..5f2701a 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -722,36 +722,37 @@ const plugin = definePlugin({ total: number; }; - let reminded = 0; + // Build case→issue map once (O(companies × issues)) to avoid N×M RPCs per stale case const companies = await ctx.companies.list(); - for (const staleCase of data.cases) { - for (const company of companies) { - const issues = await ctx.issues.list({ companyId: company.id }); - let linkedIssueId: string | null = null; - for (const issue of issues) { - const linkedCase = await ctx.state.get({ - scopeKind: "issue", - scopeId: issue.id, - stateKey: "legal-case-number", - }); - if (linkedCase === staleCase.case_number) { - linkedIssueId = issue.id; - break; - } + const caseIssueMap = new Map(); + for (const company of companies) { + const issues = await ctx.issues.list({ companyId: company.id }); + for (const issue of issues) { + const linkedCase = await ctx.state.get({ + scopeKind: "issue", + scopeId: issue.id, + stateKey: "legal-case-number", + }); + if (linkedCase && typeof linkedCase === "string") { + caseIssueMap.set(linkedCase, { issueId: issue.id, companyId: company.id }); } - if (!linkedIssueId) continue; - - await ctx.issues.createComment( - linkedIssueId, - `⚠️ **תיק תקוע ${staleCase.case_number}** — ${staleCase.days_stale} ימים ללא עדכון (סטטוס: ${staleCase.status}). האם נדרשת פעולה?`, - company.id, - ); - reminded++; - ctx.logger.info(`stale-case-reminder: reminded case ${staleCase.case_number} (${staleCase.days_stale}d)`); - break; // Found the company, move to next case } } + let reminded = 0; + for (const staleCase of data.cases) { + const linked = caseIssueMap.get(staleCase.case_number); + if (!linked) continue; + + await ctx.issues.createComment( + linked.issueId, + `⚠️ **תיק תקוע ${staleCase.case_number}** — ${staleCase.days_stale} ימים ללא עדכון (סטטוס: ${staleCase.status}). האם נדרשת פעולה?`, + linked.companyId, + ); + reminded++; + ctx.logger.info(`stale-case-reminder: reminded case ${staleCase.case_number} (${staleCase.days_stale}d)`); + } + ctx.logger.info(`stale-case-reminder: done. ${reminded}/${data.total} cases reminded`); }); @@ -801,6 +802,9 @@ const plugin = definePlugin({ async onWebhook(input: PluginWebhookInput): Promise { if (!pluginCtx) return; // not yet initialized + // TODO: add idempotency guard using input.requestId to prevent duplicate + // comments on rapid retries (store requestId in plugin state with ~60s TTL) + const { endpointKey, parsedBody } = input; if (endpointKey !== "case-status") return;