diff --git a/supabase/functions/_shared/railway.ts b/supabase/functions/_shared/railway.ts index b3a52eb..f9b6184 100644 --- a/supabase/functions/_shared/railway.ts +++ b/supabase/functions/_shared/railway.ts @@ -229,6 +229,31 @@ export async function setHermesSuspended(opts: { }); } +/** Busca o ID de um serviço pelo nome dentro de um projeto. Retorna null se não existir. */ +export async function findRailwayServiceByName(opts: { + token: string; + projectId: string; + name: string; +}): Promise { + const query = ` + query Project($id: String!) { + project(id: $id) { + services { edges { node { id name } } } + } + } + `; + const res = await railwayQuery<{ + project: { services: { edges: { node: { id: string; name: string } }[] } }; + }>(query, { id: opts.projectId }, opts.token); + if (res.errors?.length) { + console.error("findRailwayServiceByName errors:", JSON.stringify(res.errors)); + return null; + } + const edges = res.data?.project?.services?.edges ?? []; + const match = edges.find((e) => e.node.name === opts.name); + return match?.node.id ?? null; +} + /** Busca env+project IDs do primeiro deployment de um serviço. Útil quando vps_pool_id está null. */ export async function getServiceContext(opts: { token: string; diff --git a/supabase/functions/provision-agent/index.ts b/supabase/functions/provision-agent/index.ts index fa4d874..9e7f040 100644 --- a/supabase/functions/provision-agent/index.ts +++ b/supabase/functions/provision-agent/index.ts @@ -11,6 +11,7 @@ import { deployRailwayService, deleteTelegramWebhook, getServiceContext, + findRailwayServiceByName, upsertRailwayVariableCollection, } from "../_shared/railway.ts"; @@ -241,12 +242,32 @@ Deno.serve(async (req) => { let railwayServiceId: string; try { - railwayServiceId = await createRailwayService({ - token: RAILWAY_API_TOKEN, - projectId: pool.railway_project_id, - name: serviceName, - }); - console.log(`[provision-agent] serviço criado: ${railwayServiceId}`); + try { + railwayServiceId = await createRailwayService({ + token: RAILWAY_API_TOKEN, + projectId: pool.railway_project_id, + name: serviceName, + }); + console.log(`[provision-agent] serviço criado: ${railwayServiceId}`); + } catch (createErr) { + const msg = createErr instanceof Error ? createErr.message : String(createErr); + // Recover from "service already exists" — provavelmente sobra de attempt anterior + if (msg.includes("already exists")) { + console.warn(`[provision-agent] serviço já existe, tentando recuperar ID por nome: ${serviceName}`); + const existingId = await findRailwayServiceByName({ + token: RAILWAY_API_TOKEN, + projectId: pool.railway_project_id, + name: serviceName, + }); + if (!existingId) { + throw new Error(`Service "${serviceName}" exists but could not be located via API`); + } + railwayServiceId = existingId; + console.log(`[provision-agent] serviço existente recuperado: ${railwayServiceId}`); + } else { + throw createErr; + } + } await configureRailwayService({ token: RAILWAY_API_TOKEN,