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
- Job cron executa às 3:00 AM (timezone Lisboa)
- Valida todas as rádios sincronizadas
- Timeout de 8 segundos por stream
- 2 tentativas de retry com backoff de 1 segundo
✅ Em caso de falha, tenta fallback
- Suporta array de URLs alternativas (
fallback_urls) - Tenta URL principal primeiro
- Se falhar, itera por todas as fallback URLs
- Atualiza
stream_urlpara a URL que funcionou - Log claro indicando quando fallback foi usado
✅ Marca rádio inativa após X falhas
- Threshold de falhas: 3 consecutivas
- Threshold de tempo: 24 horas sem responder
- Contador
consecutive_failuresincrementado a cada falha - Reset automático quando stream volta a funcionar
- Campo
is_activeatualizado automaticamente
✅ Campo is_active exposto na API
- Já estava implementado anteriormente
- Disponível em
RadioResponseDto - Filtros suportam
is_active: boolean - Por padrão, API retorna apenas rádios ativas
🏗️ 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:
- Tenta URL principal
- Se falhar e houver fallbacks, tenta cada um
- Retorna resultado com
workingUrl(qual URL funcionou) - 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:
- Os campos novos serão populados automaticamente
- Rádios offline serão tratadas conforme lógica de fallback
- Após 3 falhas consecutivas, serão desativadas
- Reset automático quando voltarem online
🚀 Melhorias Futuras
- Notificações: Alertar quando rádio for desativada
- Dashboard: Visualizar saúde das rádios em tempo real
- Métricas: Uptime percentual por rádio
- Auto-recovery: Reativar automaticamente após X sucessos
- Priorização: Ordenar fallback URLs por latência/confiabilidade