Compare commits

..

1 commit

Author SHA1 Message Date
Cursor Origin
0373c5def1 Pre-computed merge for change #1 1970-01-01 00:00:00 +00:00
2 changed files with 8 additions and 36 deletions

View file

@ -1252,36 +1252,22 @@ registerPayrollRoutes(app);
const port = config.port; const port = config.port;
function startup(name: string, p: Promise<unknown>): Promise<unknown> {
return p.then(() => {
console.log(`[startup] ok ${name}`);
}).catch((e: unknown) => {
const msg = e instanceof Error ? e.message : String(e);
console.error(`[startup] FAIL ${name}: ${msg}`);
throw e;
});
}
// Fail-fast (Fase 7): antes con SQLite la app "siempre arrancaba" (creaba // Fail-fast (Fase 7): antes con SQLite la app "siempre arrancaba" (creaba
// el archivo si no existía). Con Postgres/Redis, si alguna de las 5 // el archivo si no existía). Con Postgres/Redis, si alguna de las 5
// conexiones no responde al arrancar, es mejor fallar ruidosamente que // conexiones no responde al arrancar, es mejor fallar ruidosamente que
// dejar que el primer request autenticado descubra el problema. // dejar que el primer request autenticado descubra el problema.
await Promise.all([ await Promise.all([
startup("postgres core (DATABASE_URL_CORE)", pingCoreDb()), pingCoreDb(),
startup("postgres platform (DATABASE_URL_PLATFORM)", pingPlatformDb()), pingPlatformDb(),
startup("redis iam+core", pingRedis().then((r) => { pingRedis().then((r) => {
if (!r.iam || !r.core) { if (!r.iam || !r.core) throw new Error("Redis (iam/core) no responde");
throw new Error( }),
`Redis no responde (iam=${r.iam} core=${r.core}). REDIS_URL_* debe usar el hostname de Redis URL (internal), no el UUID de Postgres.`, pingStorage().then((s) => {
); if (!s.ok) throw new Error("Storage (Contabo o disco local) no responde");
}
})),
startup("storage S3/R2", pingStorage().then((s) => {
if (!s.ok) throw new Error("Storage no responde (HeadBucket R2 o disco local)");
if (!config.isDev && !s.configured) { if (!config.isDev && !s.configured) {
throw new Error("S3_ENDPOINT/S3_BUCKET/S3_* son obligatorios fuera de desarrollo"); throw new Error("S3_ENDPOINT/S3_BUCKET/S3_* son obligatorios fuera de desarrollo");
} }
})), }),
]); ]);
Deno.serve({ port, hostname: "0.0.0.0" }, app.fetch); Deno.serve({ port, hostname: "0.0.0.0" }, app.fetch);

View file

@ -120,20 +120,6 @@ Ejemplo: `sudo docker logs migrate-pdyrt8ccp804tfmutefau0k6-052025710094`. `Unkn
El `docker stop … No such container` del helper de Coolify es ruido de limpieza, no la causa. El build de imágenes puede ser OK y el deploy igual falla en `migrate`. El `docker stop … No such container` del helper de Coolify es ruido de limpieza, no la causa. El build de imágenes puede ser OK y el deploy igual falla en `migrate`.
### `dependency api failed to start` / `api is unhealthy`
Liquibase ya corrió si ves `migrate … Exited` y acto seguido `api … Starting`. La API **no llega a escuchar** si Redis, S3 o los roles `_app` fallan (fail-fast antes de `Deno.serve`). Coolify entonces marca unhealthy en 1–2 s.
```bash
sudo docker logs api-<uuid>-<timestamp>
```
Busca `[startup] FAIL …`. Causas típicas:
- **Redis:** `REDIS_URL_IAM` / `REDIS_URL_CORE` con el UUID de **Postgres**. Redis tiene el suyo (Redis URL internal).
- **S3/R2:** faltan `S3_*` o HeadBucket falla (token Account API, Object Read & Write, bucket correcto, `S3_REGION=auto`).
- **Postgres `_app`:** Liquibase usa `*_OWNER`; el runtime usa `DATABASE_URL_PLATFORM`, `DATABASE_URL_IAM`, `DATABASE_URL_CORE` (passwords distintos).
### Coolify pide `PLATFORM_OWNER_PASSWORD`, `IAM_APP_PASSWORD`, `*_REDIS_PASSWORD`… ### Coolify pide `PLATFORM_OWNER_PASSWORD`, `IAM_APP_PASSWORD`, `*_REDIS_PASSWORD`…
Eso sale de **Reload Compose** mezclando el overlay de desarrollo. En producción **no las rellenes**. En el recurso: Compose file = `docker-compose.yml` únicamente. Borra esas 8 variables si Coolify las marcó Required. Siguen haciendo falta las URLs completas (`DATABASE_URL_*`, `REDIS_URL_*`). Eso sale de **Reload Compose** mezclando el overlay de desarrollo. En producción **no las rellenes**. En el recurso: Compose file = `docker-compose.yml` únicamente. Borra esas 8 variables si Coolify las marcó Required. Siguen haciendo falta las URLs completas (`DATABASE_URL_*`, `REDIS_URL_*`).