import { env } from "cloudflare:workers"; import { first } from "../db"; import { loadRepoById } from "../repos"; import { notifyQuietly, quiet } from "./deliver"; import { accountAdmins, repoAdmins } from "./recipients"; const DEDUPE_TTL_SECONDS = 60 * 60; type IntegrationInfo = { id: string; scope_type: "repo" | "org"; scope_id: string; kind: string; name: string }; /** Tells integration admins (repo admins or org owners) that a delivery or job died; at most once an hour each. */ async function notifyIntegrationDeadUnsafe( source: { deliveryId: string } | { jobId: string }, what: string, ): Promise { const integration = "deliveryId" in source ? await first( `SELECT i.id, i.scope_type, i.scope_id, i.kind, i.name FROM integration_deliveries d JOIN integrations i ON i.id = d.integration_id WHERE d.id = ?`, source.deliveryId, ) : await first( `SELECT i.id, i.scope_type, i.scope_id, i.kind, i.name FROM integration_jobs j JOIN integrations i ON i.id = j.integration_id WHERE j.id = ?`, source.jobId, ); if (!integration) return; const dedupeKey = `notify:integration-dead:${integration.id}`; if (await env.KV.get(dedupeKey)) return; await env.KV.put(dedupeKey, "1", { expirationTtl: DEDUPE_TTL_SECONDS }); const details = [ `${what} for the ${integration.kind.replace(/_/g, " ")} integration "${integration.name}" gave up after repeated failures.`, ]; if (integration.scope_type === "repo") { const repo = await loadRepoById(integration.scope_id); if (!repo) return; await notifyQuietly({ category: "integration", repoId: repo.id, accountId: null, access: "admin", recipients: await repoAdmins(repo.id), title: `Integration ${integration.name} is failing in ${repo.owner_name}/${repo.name}`, details, url: `/${repo.owner_name}/${repo.name}/settings/integrations`, }); return; } const org = await first<{ name: string }>("SELECT name FROM accounts WHERE id = ?", integration.scope_id); if (!org) return; await notifyQuietly({ category: "integration", repoId: null, accountId: integration.scope_id, access: "account", recipients: await accountAdmins(integration.scope_id), title: `Integration ${integration.name} is failing in ${org.name}`, details, url: `/orgs/${org.name}/integrations`, }); } export const notifyIntegrationDead = quiet("notifyIntegrationDead", notifyIntegrationDeadUnsafe);