27 lines
1.4 KiB
JavaScript
27 lines
1.4 KiB
JavaScript
import {claimAiJob,heartbeatAiJob,finishAiJob} from './ai-job-store.mjs';
|
||
|
||
export function startAiJobRunner(execute,{intervalMs=2000,concurrency=2}={}) {
|
||
const active=new Map();let stopped=false;
|
||
async function run(job) {
|
||
const controller=new AbortController();active.set(job.id,controller);
|
||
const heartbeat=setInterval(()=>{
|
||
try {if(!heartbeatAiJob(job.id,job.runId))controller.abort();}catch {controller.abort();}
|
||
},10000);
|
||
const timeout=setTimeout(()=>controller.abort(new Error('AI işi süre sınırına ulaştı. Yeniden deneyin.')),30*60*1000);
|
||
try {
|
||
const result=await execute(job,{signal:controller.signal});
|
||
controller.signal.throwIfAborted();
|
||
finishAiJob(job.id,job.runId,result);
|
||
}catch(error){
|
||
try {finishAiJob(job.id,job.runId,null,String(error.message || 'AI işi tamamlanamadı.'));}catch { /* lease expiry exposes interrupted work */ }
|
||
}finally {clearInterval(heartbeat);clearTimeout(timeout);active.delete(job.id);}
|
||
}
|
||
const tick=()=>{
|
||
if(stopped)return;
|
||
try {while(active.size<concurrency){const job=claimAiJob();if(!job)break;void run(job);}}
|
||
catch { /* keep durable work queued until the store is available */ }
|
||
};
|
||
const timer=setInterval(tick,intervalMs);timer.unref();
|
||
return {wake:tick,cancel:id=>active.get(id)?.abort(),stop:()=>{stopped=true;clearInterval(timer);for(const controller of active.values())controller.abort();}};
|
||
}
|