Add account based multiplayer hosting and bug report retention
This commit is contained in:
98
lib/bug-lifecycle.ts
Normal file
98
lib/bug-lifecycle.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import "server-only";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { start } from "workflow/api";
|
||||
import { admin, required } from "./supabase";
|
||||
import { LinearSupportClient } from "./linear-support-client";
|
||||
import { cleanupDoneBugReport } from "./bug-cleanup-workflow";
|
||||
|
||||
export async function scheduleBugCleanup(id: string) {
|
||||
if (!process.env.LINEAR_API_KEY || !process.env.LINEAR_TEAM_ID) return;
|
||||
const db = admin(),
|
||||
claim = `starting:${randomUUID()}`;
|
||||
const rows = required(
|
||||
await db.rpc("claim_bug_cleanup", { p_report: id, p_worker: claim }),
|
||||
);
|
||||
for (const report of rows) {
|
||||
try {
|
||||
const run = await start(cleanupDoneBugReport, [
|
||||
id,
|
||||
report.closed_at!,
|
||||
claim,
|
||||
]);
|
||||
required(
|
||||
await db
|
||||
.from("bug_reports")
|
||||
.update({ cleanup_run_id: run.runId, cleanup_lease_until: null })
|
||||
.eq("id", id)
|
||||
.eq("cleanup_run_id", claim)
|
||||
.select("id"),
|
||||
);
|
||||
} catch {
|
||||
console.error("Bug report cleanup remains saved for retry.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function reconcileBugStatus(id: string, force = false) {
|
||||
const db = admin();
|
||||
const lookup = await db
|
||||
.from("bug_reports")
|
||||
.select("*")
|
||||
.eq("id", id)
|
||||
.maybeSingle();
|
||||
if (lookup.error) required(lookup);
|
||||
const report = lookup.data;
|
||||
if (!report?.issue_synced || report.purge_started_at) return;
|
||||
if (report.state === "done" && !report.linear_done_synced) {
|
||||
await scheduleBugCleanup(id);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!force &&
|
||||
report.status_checked_at &&
|
||||
Date.parse(report.status_checked_at) > Date.now() - 60000
|
||||
)
|
||||
return;
|
||||
required(
|
||||
await db
|
||||
.from("bug_reports")
|
||||
.update({ status_checked_at: new Date().toISOString() })
|
||||
.eq("id", id)
|
||||
.select("id"),
|
||||
);
|
||||
const linear = new LinearSupportClient(
|
||||
process.env.LINEAR_API_KEY!,
|
||||
process.env.LINEAR_TEAM_ID!,
|
||||
process.env.LINEAR_PROJECT_ID,
|
||||
);
|
||||
const issue = await linear.issue(id);
|
||||
if (!issue) {
|
||||
if (report.state === "done") await scheduleBugCleanup(id);
|
||||
return;
|
||||
}
|
||||
if (issue.state?.type === "completed") {
|
||||
required(
|
||||
await db.rpc("set_bug_report_done", {
|
||||
p_report: id,
|
||||
p_done: true,
|
||||
p_closed_at: issue.completedAt ?? null,
|
||||
}),
|
||||
);
|
||||
// An external completed status may need normalizing to the team's Done status.
|
||||
required(
|
||||
await db
|
||||
.from("bug_reports")
|
||||
.update({
|
||||
linear_done_synced: issue.state.name.toLowerCase() === "done",
|
||||
})
|
||||
.eq("id", id)
|
||||
.eq("state", "done")
|
||||
.select("id"),
|
||||
);
|
||||
await scheduleBugCleanup(id);
|
||||
} else if (report.state === "done") {
|
||||
required(
|
||||
await db.rpc("set_bug_report_done", { p_report: id, p_done: false }),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user