A decentralized music tracking and discovery platform built on AT Protocol 🎵

refactor: enhance error handling and retry logic in submit_listens function

+50 -3
+44 -2
crates/scrobbler/src/listenbrainz/core/submit.rs
··· 1 1 use actix_web::HttpResponse; 2 - use anyhow::Error; 2 + use anyhow::{Context, Error}; 3 3 use owo_colors::OwoColorize; 4 4 use serde_json::json; 5 5 use std::sync::Arc; ··· 24 24 }, 25 25 }))); 26 26 } 27 - match scrobble_listenbrainz(pool, cache, payload, token).await { 27 + 28 + const RETRIES: usize = 5; 29 + for attempt in 1..=RETRIES { 30 + match scrobble_listenbrainz(pool, cache, &payload, token).await.with_context( 31 + || format!("Attempt {}/{}: Error submitting listens", attempt, RETRIES), 32 + ) { 33 + Ok(_) => { 34 + return Ok(HttpResponse::Ok().json(json!({ 35 + "status": "ok", 36 + "payload": { 37 + "submitted_listens": 1, 38 + "ignored_listens": 0 39 + }, 40 + }))); 41 + } 42 + Err(e) => { 43 + if !e.to_string().contains("error decoding response body") { 44 + println!("Non-retryable error: {}", e.to_string().red()); 45 + println!("{:#?}", payload); 46 + return Ok(HttpResponse::BadRequest().json(serde_json::json!({ 47 + "error": 4, 48 + "message": format!("Failed to parse listens: {}", e) 49 + }))); 50 + } 51 + println!("Retryable error on attempt {}/{}: {}", attempt, RETRIES, e.to_string().yellow()); 52 + println!("{:#?}", payload); 53 + 54 + if attempt == RETRIES { 55 + return Ok(HttpResponse::BadRequest().json(serde_json::json!({ 56 + "error": 4, 57 + "message": format!("Failed to parse listens after {} attempts: {}", RETRIES, e) 58 + }))); 59 + } 60 + 61 + tokio::time::sleep(std::time::Duration::from_secs(1)).await; 62 + } 63 + } 64 + } 65 + 66 + unreachable!(); 67 + 68 + /* match scrobble_listenbrainz(pool, cache, payload, token).await { 28 69 Ok(_) => Ok(HttpResponse::Ok().json(json!({ 29 70 "status": "ok", 30 71 "payload": { ··· 40 81 }))) 41 82 } 42 83 } 84 + */ 43 85 }
+6 -1
crates/scrobbler/src/scrobbler.rs
··· 432 432 pub async fn scrobble_listenbrainz( 433 433 pool: &Pool<Postgres>, 434 434 cache: &Cache, 435 - req: SubmitListensRequest, 435 + req: &SubmitListensRequest, 436 436 token: &str, 437 437 ) -> Result<(), Error> { 438 438 println!("Listenbrainz\n{:#?}", req); ··· 656 656 return Ok(()); 657 657 } 658 658 659 + // Temporary disable Musicbrainz search to reduce rate limiting issues 660 + // and because it often returns wrong results 661 + // we can re-enable it later with a retry mechanism 662 + /* 659 663 let query = format!( 660 664 r#"recording:"{}" AND artist:"{}""#, 661 665 scrobble.track, scrobble.artist ··· 670 674 tokio::time::sleep(std::time::Duration::from_secs(1)).await; 671 675 return Ok(()); 672 676 } 677 + */ 673 678 674 679 println!( 675 680 "{} {} - {}, skipping",