mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Fix a chicken & egg problem with queueingStructure.json monitor
ISSUE #209 Using the inode watcher on a file that doesn't exist fails, and was previously failing silently! This would result in queue mappings not updating when LibreQoS.py was executed - even though the queueingStructure.json file became available. * Replace "anyhow" with specific errors. * Track and log each step of the file monitor process for queueingStructure.json * If the watcher cannot start because the file doesn't exist, the watcher loop sleeps for 30 seconds at a time (to keep load very low) and checks if the file exists yet. If it does, it loads it and then commences watching.
This commit is contained in:
1
src/rust/Cargo.lock
generated
1
src/rust/Cargo.lock
generated
@@ -1384,6 +1384,7 @@ dependencies = [
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
thiserror = "1"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
lqos_bus = { path = "../lqos_bus" }
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::queue_structure::{
|
||||
queue_network::QueueNetwork, queue_node::QueueNode, read_queueing_structure,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use lazy_static::*;
|
||||
use parking_lot::RwLock;
|
||||
use thiserror::Error;
|
||||
use tokio::task::spawn_blocking;
|
||||
use log::{info, error};
|
||||
|
||||
lazy_static! {
|
||||
/// Global storage of the shaped devices csv data.
|
||||
@@ -48,16 +51,66 @@ pub async fn spawn_queue_structure_monitor() {
|
||||
|
||||
/// Fires up a Linux file system watcher than notifies
|
||||
/// when `ShapedDevices.csv` changes, and triggers a reload.
|
||||
fn watch_for_queueing_structure_changing() -> Result<()> {
|
||||
fn watch_for_queueing_structure_changing() -> Result<(), QueueWatcherError> {
|
||||
info!("Starting the queue structure monitor.");
|
||||
use notify::{Config, RecursiveMode, Watcher};
|
||||
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let mut watcher = notify::RecommendedWatcher::new(tx, Config::default())?;
|
||||
// Obtain the path to watch
|
||||
let watch_path = QueueNetwork::path();
|
||||
if watch_path.is_err() {
|
||||
error!("Could not create path for queuingStructure.json");
|
||||
return Err(QueueWatcherError::CannotCreatePath);
|
||||
}
|
||||
let watch_path = watch_path.unwrap();
|
||||
|
||||
watcher.watch(&QueueNetwork::path()?, RecursiveMode::NonRecursive)?;
|
||||
loop {
|
||||
let _ = rx.recv();
|
||||
log::info!("queuingStructure.csv changed");
|
||||
QUEUE_STRUCTURE.write().update();
|
||||
// File notify doesn't work for files that don't exist
|
||||
// It's quite possible that a user is just starting, and will
|
||||
// not have a queueingStructure.json yet - so we need to keep
|
||||
// trying to obtain one.
|
||||
|
||||
if !watch_path.exists() {
|
||||
info!("queueingStructure.json does not exist yet.");
|
||||
loop {
|
||||
std::thread::sleep(Duration::from_secs(30));
|
||||
if watch_path.exists() {
|
||||
info!("queueingStructure.json was just created. Sleeping 1 second and watching it.");
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
QUEUE_STRUCTURE.write().update();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the monitor
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let watcher = notify::RecommendedWatcher::new(tx, Config::default());
|
||||
if watcher.is_err() {
|
||||
error!("Could not create file watcher for queueingStructure.json");
|
||||
error!("{:?}", watcher);
|
||||
return Err(QueueWatcherError::WatcherFail);
|
||||
}
|
||||
let mut watcher = watcher.unwrap();
|
||||
|
||||
// Start monitoring
|
||||
let result = watcher.watch(&watch_path, RecursiveMode::NonRecursive);
|
||||
if result.is_ok() {
|
||||
info!("Watching queueingStructure.csv for changes.");
|
||||
loop {
|
||||
let _ = rx.recv();
|
||||
log::info!("queuingStructure.csv changed");
|
||||
QUEUE_STRUCTURE.write().update();
|
||||
}
|
||||
} else {
|
||||
error!("Unable to start queueingStructure watcher.");
|
||||
error!("{:?}", watcher);
|
||||
Err(QueueWatcherError::WatcherFail)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum QueueWatcherError {
|
||||
#[error("Could not create the path buffer to find queuingStructure.json")]
|
||||
CannotCreatePath,
|
||||
#[error("Cannot watch queueingStructure.json")]
|
||||
WatcherFail,
|
||||
}
|
||||
Reference in New Issue
Block a user