From 4d6de15a97b7d13b595c2a0f88634ecef8ae888c Mon Sep 17 00:00:00 2001 From: Jason Gray Date: Fri, 30 Jun 2023 02:30:14 -0500 Subject: [PATCH] Discovery retry (#1178) When started at boot as a service discovery may fail due to it trying to bind to interfaces before the network is actually up. This could be prevented in systemd by starting the service after network-online.target but it requires that a wait-online.service is also enabled which is not always the case since a wait-online.service can potentially hang the boot process until it times out in certain situations. This allows for discovery to retry every 10 secs in the 1st 60 secs of uptime before giving up thus papering over the issue and not holding up the boot process. --- CHANGELOG.md | 1 + Cargo.lock | 1 + Cargo.toml | 1 + src/main.rs | 56 ++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0de0ad1f..5b057082 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ https://github.com/librespot-org/librespot - [playback] Add metadata support via a `TrackChanged` event - [connect] Add `activate` and `load` functions to `Spirc`, allowing control over local connect sessions - [metadata] Add `Lyrics` +- [discovery] Add discovery initialisation retries if within the 1st min of uptime ### Fixed diff --git a/Cargo.lock b/Cargo.lock index 51682c4a..1f301939 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1355,6 +1355,7 @@ dependencies = [ "log", "rpassword", "sha1", + "sysinfo", "thiserror", "tokio", "url", diff --git a/Cargo.toml b/Cargo.toml index 98b8405b..1f380a1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ hex = "0.4" log = "0.4" rpassword = "7.0" sha1 = "0.10" +sysinfo = { version = "0.29", default-features = false } thiserror = "1.0" tokio = { version = "1", features = ["rt", "macros", "signal", "sync", "parking_lot", "process"] } url = "2.2" diff --git a/src/main.rs b/src/main.rs index 48edf1c9..e8c2e66f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +use futures_util::StreamExt; +use log::{debug, error, info, trace, warn}; +use sha1::{Digest, Sha1}; use std::{ env, fs::create_dir_all, @@ -8,10 +11,7 @@ use std::{ str::FromStr, time::{Duration, Instant}, }; - -use futures_util::StreamExt; -use log::{error, info, trace, warn}; -use sha1::{Digest, Sha1}; +use sysinfo::{System, SystemExt}; use thiserror::Error; use url::Url; @@ -1646,6 +1646,7 @@ fn get_setup() -> Setup { async fn main() { const RUST_BACKTRACE: &str = "RUST_BACKTRACE"; const RECONNECT_RATE_LIMIT_WINDOW: Duration = Duration::from_secs(600); + const DISCOVERY_RETRY_TIMEOUT: Duration = Duration::from_secs(10); const RECONNECT_RATE_LIMIT: usize = 5; if env::var(RUST_BACKTRACE).is_err() { @@ -1664,18 +1665,43 @@ async fn main() { let mut session = Session::new(setup.session_config.clone(), setup.cache.clone()); + let mut sys = System::new(); + if setup.enable_discovery { - let device_id = setup.session_config.device_id.clone(); - let client_id = setup.session_config.client_id.clone(); - match librespot::discovery::Discovery::builder(device_id, client_id) - .name(setup.connect_config.name.clone()) - .device_type(setup.connect_config.device_type) - .port(setup.zeroconf_port) - .zeroconf_ip(setup.zeroconf_ip) - .launch() - { - Ok(d) => discovery = Some(d), - Err(err) => warn!("Could not initialise discovery: {}.", err), + // When started at boot as a service discovery may fail due to it + // trying to bind to interfaces before the network is actually up. + // This could be prevented in systemd by starting the service after + // network-online.target but it requires that a wait-online.service is + // also enabled which is not always the case since a wait-online.service + // can potentially hang the boot process until it times out in certain situations. + // This allows for discovery to retry every 10 secs in the 1st min of uptime + // before giving up thus papering over the issue and not holding up the boot process. + + discovery = loop { + let device_id = setup.session_config.device_id.clone(); + let client_id = setup.session_config.client_id.clone(); + + match librespot::discovery::Discovery::builder(device_id, client_id) + .name(setup.connect_config.name.clone()) + .device_type(setup.connect_config.device_type) + .port(setup.zeroconf_port) + .zeroconf_ip(setup.zeroconf_ip.clone()) + .launch() + { + Ok(d) => break Some(d), + Err(e) => { + sys.refresh_processes(); + + if sys.uptime() <= 1 { + debug!("Retrying to initialise discovery: {e}"); + tokio::time::sleep(DISCOVERY_RETRY_TIMEOUT).await; + } else { + debug!("System uptime > 1 min, not retrying to initialise discovery"); + warn!("Could not initialise discovery: {e}"); + break None; + } + } + } }; }