NPM punta a nginx locale su :3000 che resta attivo durante il restart Rails; nuovo script release_production.sh esegue migrate, build e deploy in ordine. Co-authored-by: Cursor <cursoragent@cursor.com>
143 lines
4.9 KiB
Markdown
143 lines
4.9 KiB
Markdown
# Monitoraggio ops — Match Live TV
|
|
|
|
Sistema integrato per health check continui, analisi log, dashboard incidenti e notifiche push.
|
|
|
|
## Componenti
|
|
|
|
| Componente | Ruolo |
|
|
|------------|-------|
|
|
| `Ops::HealthMonitorJob` | Sidekiq — health check ogni ~3 min |
|
|
| `Ops::HealthChecks` | Disco, DB, Redis, MediaMTX, Garage, Sidekiq, HTTP pubblico |
|
|
| `Ops::LogScanner` | Pattern regex su log Docker (cron ogni 10 min) |
|
|
| `Ops::Incident` | DB — incidenti con deduplicazione |
|
|
| `Ops::Notifier` | Push ntfy + email opzionale |
|
|
| `/admin/ops` | Dashboard incidenti |
|
|
| `GET /up/deep` | Health check esteso (JSON) |
|
|
|
|
## Setup notifiche ntfy self-hosted (telefono)
|
|
|
|
Le push **ops** (disco pieno, Sidekiq, servizi giù) non passano da Firebase: Rails invia un POST al server **ntfy** incluso in `docker-compose.prod.yml`.
|
|
|
|
### 1. Server (Docker)
|
|
|
|
```bash
|
|
cd /opt/matchlivetv/infra
|
|
docker compose -f docker-compose.prod.yml --env-file .env up -d ntfy
|
|
```
|
|
|
|
Servizio in ascolto su **LAN** `http://192.168.1.146:8090` (non esporre 8090 su Internet).
|
|
|
|
### 2. HTTPS (Nginx Proxy Manager)
|
|
|
|
Crea un **Proxy Host** (consigliato sottodominio dedicato):
|
|
|
|
| Campo | Valore |
|
|
|-------|--------|
|
|
| Domain | `ntfy.matchlivetv.it` |
|
|
| Forward | `http://192.168.1.146:8090` |
|
|
| WebSockets | **ON** |
|
|
| SSL | Let's Encrypt |
|
|
|
|
In `infra/.env`:
|
|
|
|
```bash
|
|
NTFY_PUBLIC_URL=https://ntfy.matchlivetv.it
|
|
OPS_NTFY_TOPIC=matchlivetv-ops-eminux-a8f3b2 # topic segreto, a piacere
|
|
OPS_NTFY_URL=http://ntfy:80/matchlivetv-ops-eminux-a8f3b2
|
|
OPS_NOTIFY_SEVERITIES=critical,warning
|
|
OPS_NOTIFY_COOLDOWN_MINUTES=30
|
|
```
|
|
|
|
`OPS_NTFY_URL` usa il nome Docker `ntfy` (rete interna). Il telefono usa invece `NTFY_PUBLIC_URL`.
|
|
|
|
### 3. App sul telefono
|
|
|
|
1. Installa [ntfy](https://ntfy.sh) (Android/iOS)
|
|
2. **Impostazioni → Default server** (o «Usa altro server») → `https://ntfy.matchlivetv.it`
|
|
In casa, in alternativa: `http://192.168.1.146:8090`
|
|
3. **+** → iscriviti al topic `OPS_NTFY_TOPIC` (es. `matchlivetv-ops-eminux-a8f3b2`)
|
|
4. Abilita notifiche per quel topic
|
|
|
|
### 4. Test
|
|
|
|
```bash
|
|
docker compose -f docker-compose.prod.yml exec -T rails bundle exec rails ops:test_notify
|
|
```
|
|
|
|
Dovresti ricevere una push «Test notifica ops» sul telefono.
|
|
|
|
### Sicurezza
|
|
|
|
- Il topic è la «password»: usa un nome lungo e casuale, non pubblicarlo
|
|
- Opzionale: abilita auth su ntfy (`OPS_NTFY_TOKEN` + utente in `user.db`) per topic protetti
|
|
|
|
## Variabili ambiente
|
|
|
|
Vedi [`infra/.env.production.example`](../infra/.env.production.example).
|
|
|
|
| Variabile | Default | Descrizione |
|
|
|-----------|---------|-------------|
|
|
| `OPS_NTFY_URL` | — | URL POST ntfy |
|
|
| `OPS_NTFY_TOKEN` | — | Bearer token (topic protetto) |
|
|
| `OPS_ALERT_EMAIL` | — | Fallback email |
|
|
| `OPS_HEALTH_INTERVAL_SECS` | 180 | Intervallo health job |
|
|
| `OPS_HEALTH_TOKEN` | — | Token per `/up/deep` |
|
|
| `OPS_DISK_CRIT_PERCENT` | 90 | Soglia critical disco |
|
|
| `OPS_LOG_SUBSCRIBER` | false | Cattura 500 in-process |
|
|
|
|
## Cron produzione
|
|
|
|
```bash
|
|
cd /opt/matchlivetv/infra && bash scripts/install_production_cron.sh
|
|
```
|
|
|
|
| Schedule | Task |
|
|
|----------|------|
|
|
| ogni 3 min (Sidekiq) | `Ops::HealthMonitorJob` |
|
|
| `*/10 * * * *` | `scan_ops_logs.sh` → `ops:ingest_logs` |
|
|
|
|
## Uptime Kuma (consigliato)
|
|
|
|
Watchdog esterno se Rails è completamente giù:
|
|
|
|
- HTTP: `https://www.matchlivetv.it/up`
|
|
- HTTP deep: `https://www.matchlivetv.it/up/deep` (header `X-Ops-Token`)
|
|
- TCP: porta 1935 (RTMP)
|
|
- Notifica: stesso topic ntfy
|
|
|
|
## Workflow rilascio
|
|
|
|
1. `cd backend && bundle exec rspec` (o equivalente in Docker dev)
|
|
2. Ciclo patch/test fino a 0 failure
|
|
3. `git commit` → `git push`
|
|
4. **`bash scripts/deploy/release_production.sh`** (sync + deploy con pagina di cortesia)
|
|
- In alternativa manuale: sync → sul server `bash scripts/deploy/release_production.sh --local`
|
|
5. Smoke test:
|
|
- `curl -sf https://www.matchlivetv.it/up`
|
|
- `bundle exec rails ops:health_check` (nel container)
|
|
- Apri `/admin/ops`
|
|
|
|
### Downtime durante il rilascio
|
|
|
|
| Componente | Comportamento |
|
|
|------------|---------------|
|
|
| `edge` (nginx :3000) | Resta sempre su — NPM non vede mai connection refused |
|
|
| Rails in restart | Pagina di cortesia HTML (auto-refresh 15s), non 502 NPM |
|
|
| RTMP :1935 / replay | Non toccati dal rilascio web |
|
|
| `/up` | Pass-through diretto (monitoraggio ops vede il breve gap) |
|
|
|
|
Config edge: [`infra/nginx-edge/`](../infra/nginx-edge/). Script: [`scripts/deploy/release_production.sh`](../scripts/deploy/release_production.sh).
|
|
|
|
## Sentry (opzionale)
|
|
|
|
Imposta `SENTRY_DSN` dopo `bundle install`. Gli errori creano anche incidenti ops.
|
|
|
|
## Troubleshooting
|
|
|
|
| Problema | Azione |
|
|
|----------|--------|
|
|
| Nessuna push | Verifica `OPS_NTFY_URL`, test con `ops:test_notify` |
|
|
| Troppi alert | Aumenta `OPS_NOTIFY_COOLDOWN_MINUTES`, usa Mute 24h in admin |
|
|
| Sidekiq stale | Verifica container `sidekiq` e log Sidekiq |
|
|
| Log scanner vuoto | Controlla `${MATCHLIVETV_VIDEOS_ROOT}/log/cron-ops.log` (es. `/media/videos/matchlivetv/log/cron-ops.log`) |
|