feat(infra): apps/api e apps/frontend como services systemd
Fecha um risco documentado desde a PHASE 01: os dois processos de host (fora do Docker) não sobreviviam a um reboot da VM, precisando ser religados manualmente toda vez. Agora são b2bcall-api.service e b2bcall-frontend.service (infrastructure/systemd/), enabled, sobrevivem a reboot como os containers Docker já sobreviviam via restart: unless-stopped. Achado real resolvido antes de instalar: sem porta fixa, os dois disputavam a 3000 por padrão — quem perdesse crashava com EADDRINUSE em vez de cair pra 3001. Fixado API_PORT=3000 (.env) e PORT=3001 (Environment= direto na unit do frontend — confirmado que colocar em apps/frontend/.env.local não funciona, o CLI do Next.js decide a porta antes de aplicar esse arquivo). A ordem de start deixa de importar. Rodam em modo dev (pnpm dev), não build de produção — decisão deliberada documentada no README, virar produção é escopo maior. Testado ponta a ponta: units instaladas e habilitadas, subiram nas portas certas sem fallback nem crash, journalctl com logs limpos, smoke test de regressão nas 19 telas do tenant + platform via os processos supervisionados, todas 200. Achado incidental: as rotas do Next.js dev levam 10-15s pra compilar na primeira visita — explica os TimeoutError intermitentes do Puppeteer vistos ao longo da sessão, não é um bug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
This commit is contained in:
57
infrastructure/systemd/README.md
Normal file
57
infrastructure/systemd/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# systemd — apps/api e apps/frontend
|
||||
|
||||
`apps/api` e `apps/frontend` rodam direto no host (fora do Docker — só
|
||||
Postgres/Redis/FreeSWITCH/fs-config/fs-events/predictive-dialer/ai-worker são
|
||||
containers, e esses já voltam sozinhos via `restart: unless-stopped` do
|
||||
`docker-compose.yml` + `docker.service` habilitado). Até a PHASE 38 os dois
|
||||
processos de host tinham que ser religados manualmente depois de qualquer
|
||||
reboot — estas units resolvem isso.
|
||||
|
||||
## Por que os dois rodam em `pnpm dev`, não build de produção
|
||||
|
||||
Decisão deliberada: o ambiente inteiro (`ACESSO_TESTE.md`) já é descrito como
|
||||
desenvolvimento/teste, não produção. Migrar `apps/api` pra `pnpm build && node
|
||||
dist/main.js` e `apps/frontend` pra `next build && next start` é uma mudança
|
||||
maior (variar comportamento de erro, HMR, etc.) fora do escopo de "sobreviver a
|
||||
um reboot" — fica pra quando o projeto realmente for pra produção.
|
||||
|
||||
## Instalação
|
||||
|
||||
```bash
|
||||
sudo cp infrastructure/systemd/b2bcall-api.service /etc/systemd/system/
|
||||
sudo cp infrastructure/systemd/b2bcall-frontend.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now b2bcall-api.service
|
||||
sudo systemctl enable --now b2bcall-frontend.service
|
||||
```
|
||||
|
||||
## Por que a ordem nunca mais importa
|
||||
|
||||
`API_PORT=3000` fixo em `.env` (lido via `EnvironmentFile=` na unit do
|
||||
`b2bcall-api`) e `PORT=3001` fixo via `Environment=` na unit do
|
||||
`b2bcall-frontend` — achado real desta sessão: sem os dois explícitos, os dois
|
||||
processos disputavam a porta 3000 por padrão, e quem perdesse a corrida caía
|
||||
pra 3001 (Next.js) ou **crashava direto** (`EADDRINUSE`, Nest/Fastify não tem
|
||||
fallback automático). Com as duas portas fixas, a ordem de start deixa de
|
||||
importar — cada um já nasce na porta certa, nunca compete pela mesma.
|
||||
|
||||
Note-se que `PORT=3001` só funciona quando setado no **ambiente do processo**
|
||||
(`Environment=` na unit, ou `PORT=3001 pnpm dev` manual) — colocar em
|
||||
`apps/frontend/.env.local` sozinho não basta: o CLI do Next.js decide a porta
|
||||
antes de aplicar esse arquivo, então só o fallback automático (achar 3000
|
||||
ocupada, tentar 3001) resolveria, e só por sorte de ordem.
|
||||
|
||||
## Comandos úteis
|
||||
|
||||
```bash
|
||||
sudo systemctl status b2bcall-api.service b2bcall-frontend.service
|
||||
journalctl -u b2bcall-api.service -f
|
||||
journalctl -u b2bcall-frontend.service -f
|
||||
sudo systemctl restart b2bcall-api.service # depois de mudar código do backend
|
||||
sudo systemctl restart b2bcall-frontend.service # depois de mudar dependencias do frontend
|
||||
```
|
||||
|
||||
`apps/api` recompila (`tsc`) toda vez que a unit inicia/reinicia — leva uns
|
||||
15-20s. `apps/frontend` (`next dev`) é bem mais rápido pra subir, mas cada
|
||||
rota ainda compila na primeira vez que é visitada (comportamento normal do
|
||||
modo dev do Next.js, não um problema desta unit).
|
||||
20
infrastructure/systemd/b2bcall-api.service
Normal file
20
infrastructure/systemd/b2bcall-api.service
Normal file
@@ -0,0 +1,20 @@
|
||||
[Unit]
|
||||
Description=B2BCall API (NestJS/Fastify)
|
||||
After=network-online.target docker.service
|
||||
Wants=network-online.target
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/b2bcall/apps/api
|
||||
EnvironmentFile=/opt/b2bcall/.env
|
||||
ExecStart=/usr/bin/pnpm dev
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=root
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=b2bcall-api
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
20
infrastructure/systemd/b2bcall-frontend.service
Normal file
20
infrastructure/systemd/b2bcall-frontend.service
Normal file
@@ -0,0 +1,20 @@
|
||||
[Unit]
|
||||
Description=B2BCall Frontend (Next.js dev server)
|
||||
After=network-online.target b2bcall-api.service
|
||||
Wants=network-online.target
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/b2bcall/apps/frontend
|
||||
Environment=PORT=3001
|
||||
ExecStart=/usr/bin/pnpm dev
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=root
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=b2bcall-frontend
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user