Suno SDK: quando a tarefa conclui, mas o download ainda falha
Um problema comum em APIs assíncronas é confundir "a tarefa terminou" com "o arquivo final está acessível".
No teste do Suno SDK pela Crazyrouter, a tarefa suno/generate chegou a succeeded, mas a URL pública de conteúdo retornou 404/502. A geração em si não tinha falhado. O problema estava na resolução da URL final.
Resultado do polling
A tarefa testada foi:
task_ac90b23619334516
O polling retornou:
{
"status": "succeeded",
"format": "mp4",
"url": "https://crazyrouter.com/v1/videos/task_ac90b23619334516/content"
}
Olhando só isso, parece que basta baixar a URL em url.
Na prática, não foi o que aconteceu.
O que falhou
Validei a URL pública de conteúdo de algumas formas:
HEAD crazyrouter.com content URL: HTTP 404
HEAD api.crazyrouter.com content URL + Authorization: HTTP 404
GET api.crazyrouter.com content URL + Authorization: HTTP 502
Se o log parasse aqui, a conclusão errada seria:
Suno falhou
Mas essa conclusão não é precisa.
O que funcionou
No detalhe bruto da tarefa, havia os campos reais do resultado upstream:
data.data.resultJson.data[0].audio_url
data.data.resultJson.data[0].image_url
O audio_url passou na validação:
HEAD audio_url: HTTP 200, Content-Type: audio/mp3
GET audio_url: HTTP 200, Content-Type: audio/mp3, 412326 bytes
Então o diagnóstico correto foi:
a geração funcionou
o polling funcionou
o proxy público /content não resolveu a URL real do áudio
o audio_url upstream estava válido
Tabela curta do teste
| Item | Resultado |
|---|---|
| Envio da tarefa | Funcionou |
| Polling | Funcionou, status succeeded |
URL pública /content | Falhou com 404/502 |
resultJson.data[0].audio_url | Funcionou, MP3 baixado |
| Estado prático | Usável, desde que o backend leia a URL real |
Como eu implementaria a validação
Eu não salvaria automaticamente qualquer resposta como .mp3 ou .mp4.
Antes disso, validaria:
HTTP status: 200 ou 206
Content-Type: audio/* ou video/*
Tamanho: maior que uma página de erro
Opcional: ffprobe ou validação equivalente
Também separaria os tipos de falha:
task_failed
content_unavailable
invalid_media_response
download_timeout
Isso ajuda bastante em produção, porque nem todo erro depois do succeeded é erro do modelo.
Estratégia simples de retry
Um fluxo razoável:
1. Tentar baixar logo após succeeded
2. Se falhar, tentar de novo em 10 segundos
3. Tentar em 30 segundos
4. Tentar em 60 segundos
5. Reconsultar o resultJson e procurar audio_url
Se ainda assim não houver arquivo válido, o erro deve ser registrado como indisponibilidade de conteúdo, não necessariamente falha de geração.
Conclusão
A principal lição do teste:
/content falhou != Suno falhou
No caso testado, o áudio existia e estava acessível via audio_url. O backend precisava apenas resolver esse campo corretamente.
Para quem está integrando Suno em um produto, esse é o ponto que eu não deixaria para depois.