# 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 Rails (critical), latenza p95 `/up`, HTTP pubblico (warning) | | `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_HTTP_RAILS_URL` | `http://edge/up` | Check Rails via edge (no hairpin NPM) | | `OPS_HTTP_PUBLIC_INTERVAL_SECS` | 900 | Intervallo check URL pubblico (warning) | | `OPS_UP_LATENCY_WARN_MS` | 2000 | Soglia warning latenza p95 `/up` | | `OPS_UP_LATENCY_CRIT_MS` | 5000 | Soglia critical latenza p95 `/up` | | `OPS_UP_LATENCY_SAMPLES` | 60 | Campioni Redis per p95 | | `OPS_UP_LATENCY_MIN_SAMPLES` | 5 | Campioni minimi prima di alert latenza | | `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`) |