🔁

Stream Fallback

Teste e Fallback de Streams de Rádio

✅ Implementação Completa

Sistema robusto de validação de streams com fallback automático e tracking de saúde das rádios.

📋 Critérios de Aceitação

✅ Worker testa stream URLs diariamente

✅ Em caso de falha, tenta fallback

✅ Marca rádio inativa após X falhas

✅ Campo is_active exposto na API

🏗️ Arquitetura

Novos Campos no Schema

// Radio Schema
export class Radio {
  // ... campos existentes ...
  
  // Fallback URLs para streams alternativos
  @Prop({ type: [String], default: [] })
  fallback_urls: string[];

  // Health check tracking
  @Prop()
  last_checked?: Date; // Última vez que o stream foi testado

  @Prop()
  last_online?: Date; // Última vez que o stream estava online

  @Prop({ default: 0 })
  consecutive_failures: number; // Número de falhas consecutivas
}

StreamValidatorService Atualizado

async validateStream(
  streamUrl: string,
  fallbackUrls: string[] = []
): Promise<RadioValidationResult>

Comportamento:

  1. Tenta URL principal
  2. Se falhar e houver fallbacks, tenta cada um
  3. Retorna resultado com workingUrl (qual URL funcionou)
  4. Logs claros em cada tentativa

RadiosSyncService Atualizado

Constantes Configuráveis:

private readonly MAX_CONSECUTIVE_FAILURES = 3; // Desativar após 3 falhas
private readonly INACTIVE_THRESHOLD_HOURS = 24; // 24 horas sem responder

Lógica de Desativação:

// Desativa se:
// 1. Atingiu número máximo de falhas consecutivas (3)
// OU
// 2. Está offline há mais de 24 horas

🔄 Fluxo Completo

Stream Online (Sucesso)

1. Valida URL principal → ✅ Online
2. Atualiza rádio:
   - is_active: true
   - last_checked: now
   - last_online: now
   - consecutive_failures: 0 (reset)
   - stream_url: URL que funcionou

Stream Offline com Fallback

1. Valida URL principal → ❌ Offline
2. Tenta fallback_urls[0] → ✅ Online
3. Atualiza rádio:
   - is_active: true
   - stream_url: fallback_urls[0] (atualiza para fallback)
   - last_checked: now
   - last_online: now
   - consecutive_failures: 0 (reset)
   - Log: "🔄 Usando fallback URL para [nome]"

Stream Offline (1ª e 2ª falha)

1. Valida URL principal → ❌ Offline
2. Tenta todos os fallbacks → ❌ Todos offline
3. Atualiza rádio:
   - is_active: true (ainda ativa)
   - consecutive_failures: +1 (1 ou 2)
   - last_checked: now
   - Log: "⚠️ Stream offline (1/3): [nome]"

Stream Offline (3ª falha = Desativação)

1. Valida URL principal → ❌ Offline
2. Tenta todos os fallbacks → ❌ Todos offline
3. consecutive_failures = 3 ≥ MAX_CONSECUTIVE_FAILURES
4. Atualiza rádio:
   - is_active: false (DESATIVADA)
   - consecutive_failures: 3
   - last_checked: now
   - Log: "❌ Rádio desativada após 3 falhas: [nome]"

Desativação por Tempo

Se (now - last_online) ≥ 24 horas:
  - is_active: false (DESATIVADA)
  - Log: "❌ Rádio desativada por inatividade: [nome]"

📊 Exemplos de Logs

Sucesso com URL Principal

🔍 Validando stream: https://stream.example.com/radio
✅ Nova rádio adicionada: Rádio Exemplo

Sucesso com Fallback

🔍 Validando stream: https://stream1.example.com/radio
⚠️  Stream principal falhou, tentando 1 fallback URLs...
🔍 Validando stream: https://stream2.example.com/radio
✅ Fallback URL funcionando: https://stream2.example.com/radio
🔄 Usando fallback URL para Rádio Exemplo: https://stream2.example.com/radio
📝 Rádio atualizada: Rádio Exemplo

Falha Progressiva

# Sync 1
⚠️  Stream offline (1/3): Rádio Offline

# Sync 2
⚠️  Stream offline (2/3): Rádio Offline

# Sync 3
❌ Rádio desativada após 3 falhas: Rádio Offline

🎯 Configuração

Ajustar Thresholds

apps/worker/src/app/radios-sync/services/radios-sync.service.ts:

// Número de falhas antes de desativar
private readonly MAX_CONSECUTIVE_FAILURES = 3; // Alterar aqui

// Horas sem responder antes de desativar
private readonly INACTIVE_THRESHOLD_HOURS = 24; // Alterar aqui

Ajustar Validação de Streams

apps/worker/src/app/radios-sync/services/stream-validator.service.ts:

private readonly REQUEST_TIMEOUT = 8000;   // Timeout por tentativa
private readonly MAX_RETRIES = 2;          // Tentativas por URL

🔧 Scripts de Teste

Verificar Estatísticas

npm run test:stream-fallback

Output:

📻 Total de rádios: 619
✅ Rádios ativas: 615
❌ Rádios inativas: 4
🔄 Rádios com fallback URLs: 23
⚠️  Rádios com falhas consecutivas: 12

Forçar Sincronização

# Via script
npm run sync:radios

# Via API (se worker estiver rodando)
curl -X POST http://localhost:3001/radios-sync/run

📝 API Endpoints

GET /radios

# Apenas rádios ativas (padrão)
curl http://localhost:3000/radios

# Incluir inativas
curl http://localhost:3000/radios?is_active=false

# Todas as rádios
curl http://localhost:3000/radios # não filtra automaticamente

Resposta com Novos Campos

{
  "id": "...",
  "name": "Rádio Comercial",
  "stream_url": "https://stream.example.com/radio",
  "is_active": true,
  "last_checked": "2025-12-23T03:00:00.000Z",
  "last_online": "2025-12-23T03:00:00.000Z",
  "consecutive_failures": 0,
  "fallback_urls": [
    "https://backup.example.com/radio"
  ]
  // ... outros campos
}

🎉 Resultado

Implementação completa dos critérios de aceitação:

✅ Worker testa streams diariamente (3:00 AM)
✅ Fallback automático se URL principal falhar
✅ Desativação após 3 falhas ou 24h offline
✅ Campo is_active exposto na API
✅ Tracking completo de saúde (last_checked, last_online, consecutive_failures)
✅ Logs detalhados para debugging

Próxima sincronização:

🚀 Melhorias Futuras

  1. Notificações: Alertar quando rádio for desativada
  2. Dashboard: Visualizar saúde das rádios em tempo real
  3. Métricas: Uptime percentual por rádio
  4. Auto-recovery: Reativar automaticamente após X sucessos
  5. Priorização: Ordenar fallback URLs por latência/confiabilidade