128 lines
3.1 KiB
TypeScript
128 lines
3.1 KiB
TypeScript
import "server-only";
|
|
|
|
import { upsertSystemSetting } from "@/lib/db/queries";
|
|
import {
|
|
AGENT_PSD_TEMPLATES_KEY,
|
|
type AgentPsdTemplate,
|
|
} from "@/lib/agents/psd-template-config";
|
|
import { readAgentPsdTemplates } from "@/lib/agents/psd-template-settings";
|
|
|
|
const DEFAULT_PARSE_HEARTBEAT_INTERVAL_MS = 25_000;
|
|
|
|
function clampProgress(value: number) {
|
|
return Math.max(0, Math.min(99, Math.round(Number(value || 0))));
|
|
}
|
|
|
|
export async function updateAgentPsdTemplateById(params: {
|
|
templateId: string;
|
|
updatedBy: string;
|
|
updater: (template: AgentPsdTemplate) => AgentPsdTemplate;
|
|
}) {
|
|
const templates = await readAgentPsdTemplates();
|
|
const currentTemplate = templates.find((entry) => entry.id === params.templateId);
|
|
|
|
if (!currentTemplate) {
|
|
return null;
|
|
}
|
|
|
|
const nextTemplate = params.updater(currentTemplate);
|
|
await upsertSystemSetting({
|
|
key: AGENT_PSD_TEMPLATES_KEY,
|
|
value: templates.map((entry) =>
|
|
entry.id === params.templateId ? nextTemplate : entry
|
|
),
|
|
updatedBy: params.updatedBy,
|
|
});
|
|
|
|
return nextTemplate;
|
|
}
|
|
|
|
export async function updateAgentPsdTemplateParseProgress(params: {
|
|
templateId: string;
|
|
updatedBy: string;
|
|
progress: number;
|
|
stage: string;
|
|
error?: string;
|
|
restart?: boolean;
|
|
}) {
|
|
const now = new Date().toISOString();
|
|
|
|
return updateAgentPsdTemplateById({
|
|
templateId: params.templateId,
|
|
updatedBy: params.updatedBy,
|
|
updater: (template) => {
|
|
if (!params.restart && template.parseStatus !== "processing") {
|
|
return template;
|
|
}
|
|
|
|
return {
|
|
...template,
|
|
parseStatus: "processing",
|
|
parseProgress: clampProgress(params.progress),
|
|
parseStage: params.stage,
|
|
parseError: params.error,
|
|
parseStartedAt:
|
|
params.restart || !template.parseStartedAt
|
|
? now
|
|
: template.parseStartedAt,
|
|
parseHeartbeatAt: now,
|
|
updatedAt: now,
|
|
};
|
|
},
|
|
});
|
|
}
|
|
|
|
export function createAgentPsdTemplateParseHeartbeat(params: {
|
|
templateId: string;
|
|
updatedBy: string;
|
|
getSnapshot: () => {
|
|
progress: number;
|
|
stage: string;
|
|
error?: string;
|
|
};
|
|
intervalMs?: number;
|
|
}) {
|
|
let stopped = false;
|
|
let inFlight = false;
|
|
let failedBeats = 0;
|
|
|
|
const interval = setInterval(() => {
|
|
if (stopped || inFlight) {
|
|
return;
|
|
}
|
|
|
|
inFlight = true;
|
|
const snapshot = params.getSnapshot();
|
|
void updateAgentPsdTemplateParseProgress({
|
|
templateId: params.templateId,
|
|
updatedBy: params.updatedBy,
|
|
progress: snapshot.progress,
|
|
stage: snapshot.stage,
|
|
error: snapshot.error,
|
|
})
|
|
.then(() => {
|
|
failedBeats = 0;
|
|
})
|
|
.catch((error) => {
|
|
failedBeats += 1;
|
|
if (failedBeats <= 3) {
|
|
console.warn("[PSD Template] parse heartbeat update failed:", {
|
|
templateId: params.templateId,
|
|
failedBeats,
|
|
error,
|
|
});
|
|
}
|
|
})
|
|
.finally(() => {
|
|
inFlight = false;
|
|
});
|
|
}, params.intervalMs || DEFAULT_PARSE_HEARTBEAT_INTERVAL_MS);
|
|
|
|
return {
|
|
stop() {
|
|
stopped = true;
|
|
clearInterval(interval);
|
|
},
|
|
};
|
|
}
|