Correção de horario e implantação da geração de Romaneio
This commit is contained in:
119
README.md
119
README.md
@@ -3068,3 +3068,122 @@ caminho do servidor e o trace inteiro — para **qualquer pessoa** que provocass
|
||||
celular, onde não há faixa lateral livre.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary><strong>🕐 Relógio, restart automático e migrations no boot</strong></summary>
|
||||
|
||||
## O problema relatado
|
||||
|
||||
> "toda vez que faço o deploy ou reinicio o Docker a data e hora ficam erradas."
|
||||
|
||||
São **dois problemas diferentes** que se confundem porque aparecem no mesmo lugar:
|
||||
|
||||
| Sintoma | Causa | Onde se resolve |
|
||||
|---|---|---|
|
||||
| Hora **sempre 3h adiantada**, todo restart | O container subia em **UTC** | `Dockerfile` (fuso) |
|
||||
| Hora **derivando / errada depois de reboot** | Relógio do **host** sem sincronia | `deploy/ntp-seguro.sh` (NTS) |
|
||||
|
||||
### 1. Fuso do container (o "sempre 3h à frente")
|
||||
|
||||
A imagem `ruby:3.2.2-slim` sobe em UTC. O Rails até mostrava a hora certa
|
||||
(`config.time_zone = "America/Sao_Paulo"`), mas **tudo que era do sistema
|
||||
operacional continuava adiantado** — e o pior caso não era visual:
|
||||
|
||||
> **O cron rodava no horário errado.** `every "*/30 8-18"` no `config/schedule.rb`
|
||||
> executava das **05h às 15h** de Brasília, não das 08h às 18h.
|
||||
|
||||
Agora o `Dockerfile` fixa `TZ=America/Sao_Paulo` **e** o symlink de
|
||||
`/etc/localtime` — os dois, porque o cron do Debian lê o arquivo, não a
|
||||
variável. O mesmo foi feito no `whatsapp/Dockerfile` (Alpine precisa do pacote
|
||||
`tzdata`, que não vem na imagem). Dá para ajustar sem rebuild pelo `TZ` do `.env`.
|
||||
|
||||
### 2. Hora do host — NTP autenticado (NTS)
|
||||
|
||||
**Não dá para sincronizar o relógio de dentro do container**: ele lê o clock do
|
||||
kernel do host. Rodar NTP lá dentro exigiria `CAP_SYS_TIME` e mudaria a hora do
|
||||
servidor inteiro a partir de um processo da aplicação.
|
||||
|
||||
No servidor, uma vez:
|
||||
|
||||
```bash
|
||||
sudo bash deploy/ntp-seguro.sh
|
||||
```
|
||||
|
||||
O script instala e configura o **chrony com NTS** (RFC 8915): a troca de chaves
|
||||
é por TLS (TCP 4460) e os pacotes NTP vêm assinados, então uma resposta forjada
|
||||
no caminho é descartada. NTP comum é UDP sem autenticação — e hora errada aqui
|
||||
não é detalhe: ela muda **o dia da consolidação, o recorte do período financeiro
|
||||
e a validade da sessão**.
|
||||
|
||||
O script ainda: usa **3 fontes independentes** (Cloudflare, Netnod, PTB),
|
||||
**desliga as fontes não autenticadas** (deixar o `pool` padrão anularia o ganho),
|
||||
desativa o `systemd-timesyncd` (não fala NTS e brigaria pelo relógio), liga o
|
||||
`rtcsync` (é o relógio de hardware que dá a hora no boot) e mostra a
|
||||
conferência no fim. É idempotente e guarda `.bak` da config.
|
||||
|
||||
Conferir depois, a qualquer momento:
|
||||
|
||||
```bash
|
||||
chronyc tracking # 'System time' deve ficar na casa dos milissegundos
|
||||
chronyc -N authdata # NTS ativo em cada fonte (Cook > 0)
|
||||
```
|
||||
|
||||
> **Firewall:** precisa de saída em **UDP 123** e **TCP 4460**. Sem a 4460 o NTS
|
||||
> não fecha e o chrony fica sem fonte.
|
||||
|
||||
## Restart automático + migrations
|
||||
|
||||
`docker-compose.yml`, serviço `app`: **`restart: unless-stopped`**. Sobe sozinho
|
||||
depois de queda do processo e de reboot do servidor, e só fica parado se alguém
|
||||
der `docker compose stop/down`. (`always` foi descartado: ele reergue o container
|
||||
até depois de um `stop` deliberado, tirando do operador a chance de deixar o
|
||||
sistema fora do ar de propósito.)
|
||||
|
||||
O boot saiu do `command:` de uma linha só e virou **`bin/docker-boot`**, com o
|
||||
motivo de cada passo comentado:
|
||||
|
||||
1. **relógio** — imprime a hora e o fuso no log (se aparecer UTC, o rebuild não pegou);
|
||||
2. **pid órfão** — sem limpar, o Puma se recusa a subir depois de uma queda;
|
||||
3. **gems** — `bundle check || bundle install` (o volume `bundle_cache` sombreia os gems da imagem);
|
||||
4. **migrations** — `db:prepare`, **com espera pelo banco**;
|
||||
5. **cron** — `whenever --update-crontab` + daemon, *best-effort*;
|
||||
6. **Puma**.
|
||||
|
||||
Ou seja: **a migration é automática a todo restart** — `db:prepare` cria o banco
|
||||
se não existir, aplica as migrations pendentes e só faz seed em banco novo
|
||||
(idempotente). Não há passo manual depois do deploy.
|
||||
|
||||
> **Por que a espera no passo 4:** o PostgreSQL é externo ao compose. Num reboot
|
||||
> do servidor o Rails pode subir antes de o banco aceitar conexão — e agora, com
|
||||
> `restart: unless-stopped`, isso viraria um **loop de reinício** parecendo erro
|
||||
> de migration. São 10 tentativas × 6s. Se falhar depois disso (migration
|
||||
> quebrada, credencial errada), o container sai com erro **de propósito**: melhor
|
||||
> do que servir a aplicação contra um schema desatualizado.
|
||||
|
||||
## Deploy
|
||||
|
||||
```bash
|
||||
# 1. No servidor, uma única vez — relógio com NTP autenticado:
|
||||
sudo bash deploy/ntp-seguro.sh
|
||||
|
||||
# 2. Rebuild obrigatório (o fuso entra na imagem):
|
||||
docker compose up -d --build
|
||||
|
||||
# 3. Conferir no log que o container está em -03 e não em UTC:
|
||||
docker compose logs app | grep '\[boot\] relógio'
|
||||
```
|
||||
|
||||
## 📂 Arquivos
|
||||
|
||||
```
|
||||
Dockerfile # TZ=America/Sao_Paulo + tzdata + /etc/localtime; CMD -> bin/docker-boot
|
||||
whatsapp/Dockerfile # tzdata (Alpine) + mesmo fuso
|
||||
docker-compose.yml # restart: unless-stopped, TZ, command: bin/docker-boot
|
||||
bin/docker-boot # boot documentado: migrations com espera, cron, Puma — NOVO
|
||||
deploy/ntp-seguro.sh # chrony + NTS no host (rodar 1x, como root) — NOVO
|
||||
.env.example # TZ=America/Sao_Paulo + aviso "fuso ≠ hora"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Reference in New Issue
Block a user