import { loadConfig } from "@nproxy/config"; import { createPrismaWorkerStore, prisma } from "@nproxy/db"; import { createNanoBananaSimulatedAdapter } from "@nproxy/providers"; const config = loadConfig(); const intervalMs = config.keyPool.balancePollSeconds * 1000; const workerStore = createPrismaWorkerStore(prisma, { cooldownMinutes: config.keyPool.cooldownMinutes, failuresBeforeManualReview: config.keyPool.failuresBeforeManualReview, }); const nanoBananaAdapter = createNanoBananaSimulatedAdapter(); let isTickRunning = false; console.log( JSON.stringify({ service: "worker", balancePollSeconds: config.keyPool.balancePollSeconds, providerModel: config.provider.nanoBananaDefaultModel, }), ); setInterval(() => { void runTick(); }, intervalMs); void runTick(); process.once("SIGTERM", async () => { await prisma.$disconnect(); process.exit(0); }); process.once("SIGINT", async () => { await prisma.$disconnect(); process.exit(0); }); async function runTick(): Promise { if (isTickRunning) { console.log("worker tick skipped because previous tick is still running"); return; } isTickRunning = true; try { const recovery = await workerStore.recoverCooldownProviderKeys(); if (recovery.recoveredCount > 0) { console.log( JSON.stringify({ service: "worker", event: "cooldown_keys_recovered", recoveredCount: recovery.recoveredCount, }), ); } const job = await workerStore.claimNextQueuedGenerationJob(); if (!job) { console.log(`worker heartbeat interval=${intervalMs} no_queued_jobs=true`); return; } const result = await workerStore.processClaimedGenerationJob( job, async (request, providerKey) => { if (providerKey.providerCode !== config.provider.nanoBananaDefaultModel) { return { ok: false as const, usedProxy: false, directFallbackUsed: false, failureKind: "unknown" as const, providerErrorCode: "unsupported_provider_model", providerErrorText: `Unsupported provider model: ${providerKey.providerCode}`, }; } if (providerKey.proxyBaseUrl) { const proxyResult = await nanoBananaAdapter.executeGeneration({ request, providerKey: { id: providerKey.id, providerCode: providerKey.providerCode, label: providerKey.label, apiKeyLastFour: providerKey.apiKeyLastFour, }, route: { kind: "proxy", proxyBaseUrl: providerKey.proxyBaseUrl, }, }); if (!proxyResult.ok && proxyResult.failureKind === "transport") { const directResult = await nanoBananaAdapter.executeGeneration({ request, providerKey: { id: providerKey.id, providerCode: providerKey.providerCode, label: providerKey.label, apiKeyLastFour: providerKey.apiKeyLastFour, }, route: { kind: "direct", }, }); return { ...directResult, usedProxy: true, directFallbackUsed: true, }; } return { ...proxyResult, usedProxy: true, directFallbackUsed: false, }; } const directResult = await nanoBananaAdapter.executeGeneration({ request, providerKey: { id: providerKey.id, providerCode: providerKey.providerCode, label: providerKey.label, apiKeyLastFour: providerKey.apiKeyLastFour, }, route: { kind: "direct", }, }); return { ...directResult, usedProxy: false, directFallbackUsed: false, }; }, ); console.log(JSON.stringify({ service: "worker", event: "job_processed", ...result })); } catch (error) { console.error("worker tick failed", error); } finally { isTickRunning = false; } }