38 lines · 1.4 KB
import { run } from "../db";

const DELIVERY_RETENTION_MS = 30 * 24 * 60 * 60_000;
const PRUNE_BATCH = 500;

/** Integrations whose repo or org no longer exists hold live credentials for nothing; remove them. */
async function pruneOrphanedIntegrations(): Promise<void> {
  await run(
    `DELETE FROM integrations WHERE id IN (
       SELECT id FROM integrations WHERE scope_type = 'repo' AND scope_id NOT IN (SELECT id FROM repos) LIMIT ?)`,
    PRUNE_BATCH,
  );
  await run(
    `DELETE FROM integrations WHERE id IN (
       SELECT id FROM integrations WHERE scope_type = 'org' AND scope_id NOT IN (SELECT id FROM accounts) LIMIT ?)`,
    PRUNE_BATCH,
  );
}

/** Integration delivery logs (inbound and outbound) are kept for 30 days, pruned in batches. */
async function pruneDeliveryLogs(now: number): Promise<void> {
  const cutoff = now - DELIVERY_RETENTION_MS;
  await run(
    "DELETE FROM integration_deliveries WHERE id IN (SELECT id FROM integration_deliveries WHERE created_at < ? LIMIT ?)",
    cutoff,
    PRUNE_BATCH,
  );
}

/** Legacy webhook deliveries live in their repository's RepoState, whose alarm expires them (housekeeping.ts). */
export const WEBHOOK_DELIVERY_RETENTION_MS = DELIVERY_RETENTION_MS;

/** Cron tail: orphaned integrations (INT-A25) and unbounded delivery logs (INT-A27). */
export async function pruneIntegrationLeftovers(now: number): Promise<void> {
  await pruneOrphanedIntegrations();
  await pruneDeliveryLogs(now);
}