Skip to content

Commit aae9300

Browse files
committed
feat: add script to retry queued analysis jobs by re-sending Inngest events
1 parent 4a07531 commit aae9300

1 file changed

Lines changed: 128 additions & 0 deletions

File tree

scripts/retry-queued-jobs.mjs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/**
2+
* Retry all queued analysis jobs by re-sending Inngest events.
3+
*
4+
* Usage:
5+
* INNGEST_EVENT_KEY=<key> node scripts/retry-queued-jobs.mjs
6+
*
7+
* The Inngest event key can be found in the Inngest dashboard or Vercel env vars.
8+
* Supabase credentials are loaded from apps/web/.env.local / .env automatically.
9+
*/
10+
import fs from "node:fs";
11+
import path from "node:path";
12+
import { fileURLToPath } from "node:url";
13+
14+
// ── env loading (reused from supabase.mjs) ──────────────────────────────────
15+
16+
function loadDotEnvFile(filePath) {
17+
if (!fs.existsSync(filePath)) return;
18+
const contents = fs.readFileSync(filePath, "utf8").replace(/^\uFEFF/, "");
19+
for (const line of contents.split(/\r?\n/)) {
20+
const trimmed = line.trim().replace(/^export\s+/, "");
21+
if (!trimmed || trimmed.startsWith("#")) continue;
22+
const eq = trimmed.indexOf("=");
23+
if (eq === -1) continue;
24+
const key = trimmed.slice(0, eq).trim();
25+
let value = trimmed.slice(eq + 1).trim();
26+
if (
27+
(value.startsWith('"') && value.endsWith('"')) ||
28+
(value.startsWith("'") && value.endsWith("'"))
29+
) {
30+
value = value.slice(1, -1);
31+
}
32+
if (key && (process.env[key] === undefined || process.env[key] === "")) {
33+
process.env[key] = value;
34+
}
35+
}
36+
}
37+
38+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
39+
loadDotEnvFile(path.join(repoRoot, "apps/web/.env.local"));
40+
loadDotEnvFile(path.join(repoRoot, "apps/web/.env"));
41+
42+
// ── config ──────────────────────────────────────────────────────────────────
43+
44+
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL;
45+
const SERVICE_ROLE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY;
46+
const INNGEST_EVENT_KEY = process.env.INNGEST_EVENT_KEY;
47+
48+
if (!SUPABASE_URL || !SERVICE_ROLE_KEY) {
49+
console.error("Missing NEXT_PUBLIC_SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY");
50+
process.exit(1);
51+
}
52+
53+
if (!INNGEST_EVENT_KEY) {
54+
console.error(
55+
"Missing INNGEST_EVENT_KEY. Get it from the Inngest dashboard or Vercel env vars.\n" +
56+
"Usage: INNGEST_EVENT_KEY=<key> node scripts/retry-queued-jobs.mjs"
57+
);
58+
process.exit(1);
59+
}
60+
61+
// ── main ────────────────────────────────────────────────────────────────────
62+
63+
async function main() {
64+
// 1. Fetch all queued jobs
65+
const url = `${SUPABASE_URL}/rest/v1/analysis_jobs?select=id,user_id,repo_id,created_at&status=eq.queued&order=created_at.asc`;
66+
const res = await fetch(url, {
67+
headers: {
68+
apikey: SERVICE_ROLE_KEY,
69+
Authorization: `Bearer ${SERVICE_ROLE_KEY}`,
70+
},
71+
});
72+
73+
if (!res.ok) {
74+
console.error("Failed to fetch queued jobs:", res.status, await res.text());
75+
process.exit(1);
76+
}
77+
78+
const jobs = await res.json();
79+
80+
if (jobs.length === 0) {
81+
console.log("No queued jobs found.");
82+
return;
83+
}
84+
85+
console.log(`Found ${jobs.length} queued job(s). Re-sending Inngest events...\n`);
86+
87+
// 2. Send an Inngest event for each job
88+
let success = 0;
89+
let failed = 0;
90+
91+
for (const job of jobs) {
92+
const event = {
93+
name: "repo/analyze.requested",
94+
data: {
95+
jobId: job.id,
96+
userId: job.user_id,
97+
repoId: job.repo_id,
98+
},
99+
};
100+
101+
try {
102+
const inngestRes = await fetch(`https://inn.gs/e/${INNGEST_EVENT_KEY}`, {
103+
method: "POST",
104+
headers: { "Content-Type": "application/json" },
105+
body: JSON.stringify(event),
106+
});
107+
108+
if (inngestRes.ok) {
109+
console.log(` ✓ ${job.id} (created ${job.created_at})`);
110+
success++;
111+
} else {
112+
const body = await inngestRes.text();
113+
console.error(` ✗ ${job.id}: ${inngestRes.status} ${body}`);
114+
failed++;
115+
}
116+
} catch (err) {
117+
console.error(` ✗ ${job.id}: ${err.message}`);
118+
failed++;
119+
}
120+
}
121+
122+
console.log(`\nDone. ${success} sent, ${failed} failed.`);
123+
}
124+
125+
main().catch((err) => {
126+
console.error(err);
127+
process.exit(1);
128+
});

0 commit comments

Comments
 (0)