import { NextResponse } from "next/server"; import { env } from "@/lib/env"; import { syncPleskInstance } from "@/lib/plesk/sync"; import { createSupabaseAdminClient } from "@/lib/supabase/admin"; const JOB_NAME = "plesk_sync_all"; const MAX_INSTANCES_PER_RUN = 10; export async function POST(req: Request) { try { const secret = req.headers.get("x-job-secret"); if (!env.jobSecret || !secret || secret !== env.jobSecret) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const supabase = createSupabaseAdminClient() as any; const lockOwner = `nextjs:${process.pid}:${Date.now()}`; const { data: acquired, error: lockError } = await supabase.rpc( "acquire_job_lock", { p_job_name: JOB_NAME, p_locked_by: lockOwner, p_ttl_seconds: 240, }, ); if (lockError) { throw new Error(`Unable to acquire job lock: ${lockError.message}`); } if (!acquired) { return NextResponse.json({ skipped: true, reason: "already_running" }); } try { const { data: instances, error: instancesError } = await supabase .from("plesk_instances") .select( "id, agency_id, base_url, auth_type, encrypted_secret, last_connected_at", ) .eq("status", "connected") .order("last_connected_at", { ascending: true, nullsFirst: true }) .limit(MAX_INSTANCES_PER_RUN); if (instancesError) throw instancesError; const results: Array> = []; for (const instance of instances ?? []) { try { const result = await syncPleskInstance( supabase, instance, null, "plesk_sync_auto", ); results.push(result); } catch (error) { const message = error instanceof Error ? error.message.slice(0, 1000) : "Auto sync failed"; await supabase .from("plesk_instances") .update({ status: "error", error_message: message }) .eq("id", instance.id) .eq("agency_id", instance.agency_id); await supabase.from("actions_log").insert({ agency_id: instance.agency_id, actor_user_id: null, target_type: "plesk_instance", target_id: instance.id, action: "plesk_sync_auto", status: "failed", error_message: message, metadata: { auto: true }, }); results.push({ instanceId: instance.id, agencyId: instance.agency_id, skipped: false, failed: true, error: message, }); } } return NextResponse.json({ skipped: false, processed: results.length, maxPerRun: MAX_INSTANCES_PER_RUN, results, }); } finally { await supabase.rpc("release_job_lock", { p_job_name: JOB_NAME }); } } catch (error) { return NextResponse.json( { error: error instanceof Error ? error.message : "Job failed" }, { status: 500 }, ); } }