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.
This commit is contained in:
Jason Gray 2023-06-30 02:30:14 -05:00 committed by GitHub
parent e5d364b07a
commit 4d6de15a97
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 15 deletions

View file

@ -98,6 +98,7 @@ https://github.com/librespot-org/librespot
- [playback] Add metadata support via a `TrackChanged` event - [playback] Add metadata support via a `TrackChanged` event
- [connect] Add `activate` and `load` functions to `Spirc`, allowing control over local connect sessions - [connect] Add `activate` and `load` functions to `Spirc`, allowing control over local connect sessions
- [metadata] Add `Lyrics` - [metadata] Add `Lyrics`
- [discovery] Add discovery initialisation retries if within the 1st min of uptime
### Fixed ### Fixed

1
Cargo.lock generated
View file

@ -1355,6 +1355,7 @@ dependencies = [
"log", "log",
"rpassword", "rpassword",
"sha1", "sha1",
"sysinfo",
"thiserror", "thiserror",
"tokio", "tokio",
"url", "url",

View file

@ -57,6 +57,7 @@ hex = "0.4"
log = "0.4" log = "0.4"
rpassword = "7.0" rpassword = "7.0"
sha1 = "0.10" sha1 = "0.10"
sysinfo = { version = "0.29", default-features = false }
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1", features = ["rt", "macros", "signal", "sync", "parking_lot", "process"] } tokio = { version = "1", features = ["rt", "macros", "signal", "sync", "parking_lot", "process"] }
url = "2.2" url = "2.2"

View file

@ -1,3 +1,6 @@
use futures_util::StreamExt;
use log::{debug, error, info, trace, warn};
use sha1::{Digest, Sha1};
use std::{ use std::{
env, env,
fs::create_dir_all, fs::create_dir_all,
@ -8,10 +11,7 @@ use std::{
str::FromStr, str::FromStr,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use sysinfo::{System, SystemExt};
use futures_util::StreamExt;
use log::{error, info, trace, warn};
use sha1::{Digest, Sha1};
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
@ -1646,6 +1646,7 @@ fn get_setup() -> Setup {
async fn main() { async fn main() {
const RUST_BACKTRACE: &str = "RUST_BACKTRACE"; const RUST_BACKTRACE: &str = "RUST_BACKTRACE";
const RECONNECT_RATE_LIMIT_WINDOW: Duration = Duration::from_secs(600); 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; const RECONNECT_RATE_LIMIT: usize = 5;
if env::var(RUST_BACKTRACE).is_err() { 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 session = Session::new(setup.session_config.clone(), setup.cache.clone());
let mut sys = System::new();
if setup.enable_discovery { if setup.enable_discovery {
let device_id = setup.session_config.device_id.clone(); // When started at boot as a service discovery may fail due to it
let client_id = setup.session_config.client_id.clone(); // trying to bind to interfaces before the network is actually up.
match librespot::discovery::Discovery::builder(device_id, client_id) // This could be prevented in systemd by starting the service after
.name(setup.connect_config.name.clone()) // network-online.target but it requires that a wait-online.service is
.device_type(setup.connect_config.device_type) // also enabled which is not always the case since a wait-online.service
.port(setup.zeroconf_port) // can potentially hang the boot process until it times out in certain situations.
.zeroconf_ip(setup.zeroconf_ip) // This allows for discovery to retry every 10 secs in the 1st min of uptime
.launch() // before giving up thus papering over the issue and not holding up the boot process.
{
Ok(d) => discovery = Some(d), discovery = loop {
Err(err) => warn!("Could not initialise discovery: {}.", err), 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;
}
}
}
}; };
} }