fix: address reviewer feedback — regex OnceLock and restore tick rate

- Compile whitespace regex once via OnceLock instead of on every
  non-success response; makes format_error_body infallible (String
  return, no Result) eliminating the only practical failure mode
- Revert default tick rate from 100ms back to 50ms to preserve the
  existing 20-second Servarr poll cadence (tick_until_poll=400 × 50ms);
  the recv() change is the real CPU fix — the tick rate change was
  unnecessary and silently halved the data refresh rate
- Keep MANAGARR_TICK_RATE_MS as opt-in override; note that tuning it
  proportionally stretches the poll interval alongside the tick rate
This commit is contained in:
Jonathan McCumber
2026-06-28 13:00:16 -05:00
parent 6c41e0704e
commit a72b2991fd
2 changed files with 12 additions and 13 deletions
+5 -8
View File
@@ -19,7 +19,7 @@ pub struct Events {
rx: Receiver<InputEvent<Key>>, rx: Receiver<InputEvent<Key>>,
} }
const DEFAULT_TICK_RATE_MS: u64 = 100; const DEFAULT_TICK_RATE_MS: u64 = 50;
fn configured_tick_rate_ms_from(raw: Option<&str>) -> u64 { fn configured_tick_rate_ms_from(raw: Option<&str>) -> u64 {
raw raw
@@ -78,18 +78,15 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn defaults_to_a_slower_idle_tick_rate() { fn defaults_to_original_tick_rate() {
assert_eq!(DEFAULT_TICK_RATE_MS, 100); assert_eq!(DEFAULT_TICK_RATE_MS, 50);
assert_eq!(configured_tick_rate_ms_from(None), 100); assert_eq!(configured_tick_rate_ms_from(None), 50);
} }
#[test] #[test]
fn parses_positive_tick_rates_and_rejects_invalid_values() { fn parses_positive_tick_rates_and_rejects_invalid_values() {
assert_eq!(configured_tick_rate_ms_from(Some("250")), 250); assert_eq!(configured_tick_rate_ms_from(Some("250")), 250);
assert_eq!( assert_eq!(configured_tick_rate_ms_from(Some("0")), DEFAULT_TICK_RATE_MS);
configured_tick_rate_ms_from(Some("0")),
DEFAULT_TICK_RATE_MS
);
assert_eq!( assert_eq!(
configured_tick_rate_ms_from(Some("abc")), configured_tick_rate_ms_from(Some("abc")),
DEFAULT_TICK_RATE_MS DEFAULT_TICK_RATE_MS
+7 -5
View File
@@ -1,11 +1,13 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::{Arc, OnceLock};
use anyhow::{Result, anyhow}; use anyhow::{Result, anyhow};
use async_trait::async_trait; use async_trait::async_trait;
use lidarr_network::LidarrEvent; use lidarr_network::LidarrEvent;
use log::{debug, error, warn}; use log::{debug, error, warn};
use regex::Regex; use regex::Regex;
static WHITESPACE_RE: OnceLock<Regex> = OnceLock::new();
use reqwest::{Client, RequestBuilder}; use reqwest::{Client, RequestBuilder};
use serde::Serialize; use serde::Serialize;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
@@ -144,7 +146,7 @@ impl<'a, 'b> Network<'a, 'b> {
} else { } else {
let status = response.status(); let status = response.status();
let response_body = response.text().await.unwrap_or_default(); let response_body = response.text().await.unwrap_or_default();
let error_body = format_error_body(&response_body)?; let error_body = format_error_body(&response_body);
error!("Request failed. Received {status} response code with body: {response_body}"); error!("Request failed. Received {status} response code with body: {response_body}");
self.app.lock().await.handle_error(anyhow!("Request failed. Received {status} response code with body: {error_body}")); self.app.lock().await.handle_error(anyhow!("Request failed. Received {status} response code with body: {error_body}"));
@@ -277,8 +279,8 @@ impl<'a, 'b> Network<'a, 'b> {
} }
} }
fn format_error_body(response_body: &str) -> Result<String> { fn format_error_body(response_body: &str) -> String {
let whitespace_regex = Regex::new(r"\s+")?; let re = WHITESPACE_RE.get_or_init(|| Regex::new(r"\s+").unwrap());
let body = serde_json::from_str::<Value>(response_body) let body = serde_json::from_str::<Value>(response_body)
.ok() .ok()
.and_then(|value| { .and_then(|value| {
@@ -291,7 +293,7 @@ fn format_error_body(response_body: &str) -> Result<String> {
}) })
.unwrap_or_else(|| response_body.replace('\n', " ")); .unwrap_or_else(|| response_body.replace('\n', " "));
Ok(whitespace_regex.replace_all(&body, " ").to_string()) re.replace_all(&body, " ").to_string()
} }
#[derive(Clone, Copy, Debug, Display, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Display, PartialEq, Eq)]