refactor: optimize timer and network management with atomic operations

This commit is contained in:
Tunglies
2025-08-01 23:02:11 +08:00
parent 569e2d5192
commit 3eb2a5b3ef
6 changed files with 58 additions and 62 deletions

View File

@@ -1,9 +1,14 @@
use crate::{config::Config, feat, logging, logging_error, utils::logging::Type}; use crate::{config::Config, feat, logging, logging_error, singleton, utils::logging::Type};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder}; use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder};
use once_cell::sync::OnceCell; use parking_lot::RwLock;
use parking_lot::{Mutex, RwLock}; use std::{
use std::{collections::HashMap, sync::Arc}; collections::HashMap,
sync::{
atomic::{AtomicBool, AtomicU64, Ordering},
Arc,
},
};
type TaskID = u64; type TaskID = u64;
@@ -22,23 +27,24 @@ pub struct Timer {
/// save the current state - using RwLock for better read concurrency /// save the current state - using RwLock for better read concurrency
pub timer_map: Arc<RwLock<HashMap<String, TimerTask>>>, pub timer_map: Arc<RwLock<HashMap<String, TimerTask>>>,
/// increment id - kept as mutex since it's just a counter /// increment id - atomic counter for better performance
pub timer_count: Arc<Mutex<TaskID>>, pub timer_count: AtomicU64,
/// Flag to mark if timer is initialized - atomic for better performance /// Flag to mark if timer is initialized - atomic for better performance
pub initialized: Arc<std::sync::atomic::AtomicBool>, pub initialized: AtomicBool,
} }
impl Timer { // Use singleton macro
pub fn global() -> &'static Timer { singleton!(Timer, TIMER_INSTANCE);
static TIMER: OnceCell<Timer> = OnceCell::new();
TIMER.get_or_init(|| Timer { impl Timer {
fn new() -> Self {
Timer {
delay_timer: Arc::new(RwLock::new(DelayTimerBuilder::default().build())), delay_timer: Arc::new(RwLock::new(DelayTimerBuilder::default().build())),
timer_map: Arc::new(RwLock::new(HashMap::new())), timer_map: Arc::new(RwLock::new(HashMap::new())),
timer_count: Arc::new(Mutex::new(1)), timer_count: AtomicU64::new(1),
initialized: Arc::new(std::sync::atomic::AtomicBool::new(false)), initialized: AtomicBool::new(false),
}) }
} }
/// Initialize timer with better error handling and atomic operations /// Initialize timer with better error handling and atomic operations
@@ -46,12 +52,7 @@ impl Timer {
// Use compare_exchange for thread-safe initialization check // Use compare_exchange for thread-safe initialization check
if self if self
.initialized .initialized
.compare_exchange( .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
false,
true,
std::sync::atomic::Ordering::SeqCst,
std::sync::atomic::Ordering::SeqCst,
)
.is_err() .is_err()
{ {
logging!(debug, Type::Timer, "Timer already initialized, skipping..."); logging!(debug, Type::Timer, "Timer already initialized, skipping...");
@@ -63,8 +64,7 @@ impl Timer {
// Initialize timer tasks // Initialize timer tasks
if let Err(e) = self.refresh() { if let Err(e) = self.refresh() {
// Reset initialization flag on error // Reset initialization flag on error
self.initialized self.initialized.store(false, Ordering::SeqCst);
.store(false, std::sync::atomic::Ordering::SeqCst);
logging_error!(Type::Timer, false, "Failed to initialize timer: {}", e); logging_error!(Type::Timer, false, "Failed to initialize timer: {}", e);
return Err(e); return Err(e);
} }
@@ -299,7 +299,8 @@ impl Timer {
} }
// Find new tasks to add // Find new tasks to add
let mut next_id = *self.timer_count.lock(); let mut next_id = self.timer_count.load(Ordering::Relaxed);
let original_id = next_id;
for (uid, &interval) in new_map.iter() { for (uid, &interval) in new_map.iter() {
if !timer_map.contains_key(uid) { if !timer_map.contains_key(uid) {
@@ -316,8 +317,8 @@ impl Timer {
} }
// Update counter only if we added new tasks // Update counter only if we added new tasks
if next_id > *self.timer_count.lock() { if next_id > original_id {
*self.timer_count.lock() = next_id; self.timer_count.store(next_id, Ordering::Relaxed);
} }
logging!(debug, Type::Timer, "定时任务变更数量: {}", diff_map.len()); logging!(debug, Type::Timer, "定时任务变更数量: {}", diff_map.len());

View File

@@ -8,11 +8,10 @@ pub fn use_script(
name: String, name: String,
) -> Result<(Mapping, Vec<(String, String)>)> { ) -> Result<(Mapping, Vec<(String, String)>)> {
use boa_engine::{native_function::NativeFunction, Context, JsValue, Source}; use boa_engine::{native_function::NativeFunction, Context, JsValue, Source};
use parking_lot::Mutex; use std::{cell::RefCell, rc::Rc};
use std::sync::Arc;
let mut context = Context::default(); let mut context = Context::default();
let outputs = Arc::new(Mutex::new(vec![])); let outputs = Rc::new(RefCell::new(vec![]));
let copy_outputs = outputs.clone(); let copy_outputs = outputs.clone();
unsafe { unsafe {
@@ -25,7 +24,7 @@ pub fn use_script(
let level = level.to_std_string().unwrap(); let level = level.to_std_string().unwrap();
let data = args.get(1).unwrap().to_string(context)?; let data = args.get(1).unwrap().to_string(context)?;
let data = data.to_std_string().unwrap(); let data = data.to_std_string().unwrap();
let mut out = copy_outputs.lock(); let mut out = copy_outputs.borrow_mut();
out.push((level, data)); out.push((level, data));
Ok(JsValue::undefined()) Ok(JsValue::undefined())
}, },
@@ -68,7 +67,7 @@ pub fn use_script(
// 直接解析JSON结果,不做其他解析 // 直接解析JSON结果,不做其他解析
let res: Result<Mapping, Error> = parse_json_safely(&result); let res: Result<Mapping, Error> = parse_json_safely(&result);
let mut out = outputs.lock(); let mut out = outputs.borrow_mut();
match res { match res {
Ok(config) => Ok((use_lowercase(config), out.to_vec())), Ok(config) => Ok((use_lowercase(config), out.to_vec())),
Err(err) => { Err(err) => {

View File

@@ -162,6 +162,7 @@ mod app_init {
/// Setup plugins for the Tauri builder /// Setup plugins for the Tauri builder
pub fn setup_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> { pub fn setup_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
#[allow(unused_mut)]
let mut builder = builder let mut builder = builder
.plugin(tauri_plugin_notification::init()) .plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_updater::Builder::new().build()) .plugin(tauri_plugin_updater::Builder::new().build())

View File

@@ -254,10 +254,9 @@ fn setup_light_weight_timer() -> Result<()> {
// 获取task_id // 获取task_id
let task_id = { let task_id = {
let mut timer_count = Timer::global().timer_count.lock(); Timer::global()
let id = *timer_count; .timer_count
*timer_count += 1; .fetch_add(1, std::sync::atomic::Ordering::Relaxed)
id
}; };
// 创建任务 // 创建任务

View File

@@ -2,7 +2,10 @@ use anyhow::Result;
use parking_lot::Mutex; use parking_lot::Mutex;
use reqwest::{Client, ClientBuilder, Proxy, RequestBuilder, Response}; use reqwest::{Client, ClientBuilder, Proxy, RequestBuilder, Response};
use std::{ use std::{
sync::{Arc, Once}, sync::{
atomic::{AtomicUsize, Ordering},
Arc, Once,
},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tokio::runtime::{Builder, Runtime}; use tokio::runtime::{Builder, Runtime};
@@ -23,12 +26,12 @@ const POOL_IDLE_TIMEOUT: Duration = Duration::from_secs(15);
/// 网络管理器 /// 网络管理器
pub struct NetworkManager { pub struct NetworkManager {
runtime: Arc<Runtime>, runtime: Arc<Runtime>,
self_proxy_client: Arc<Mutex<Option<Client>>>, self_proxy_client: Mutex<Option<Client>>,
system_proxy_client: Arc<Mutex<Option<Client>>>, system_proxy_client: Mutex<Option<Client>>,
no_proxy_client: Arc<Mutex<Option<Client>>>, no_proxy_client: Mutex<Option<Client>>,
init: Once, init: Once,
last_connection_error: Arc<Mutex<Option<(Instant, String)>>>, last_connection_error: Mutex<Option<(Instant, String)>>,
connection_error_count: Arc<Mutex<usize>>, connection_error_count: AtomicUsize,
} }
// Use singleton_lazy macro to replace lazy_static! // Use singleton_lazy macro to replace lazy_static!
@@ -47,12 +50,12 @@ impl NetworkManager {
NetworkManager { NetworkManager {
runtime: Arc::new(runtime), runtime: Arc::new(runtime),
self_proxy_client: Arc::new(Mutex::new(None)), self_proxy_client: Mutex::new(None),
system_proxy_client: Arc::new(Mutex::new(None)), system_proxy_client: Mutex::new(None),
no_proxy_client: Arc::new(Mutex::new(None)), no_proxy_client: Mutex::new(None),
init: Once::new(), init: Once::new(),
last_connection_error: Arc::new(Mutex::new(None)), last_connection_error: Mutex::new(None),
connection_error_count: Arc::new(Mutex::new(0)), connection_error_count: AtomicUsize::new(0),
} }
} }
@@ -85,12 +88,11 @@ impl NetworkManager {
let mut last_error = self.last_connection_error.lock(); let mut last_error = self.last_connection_error.lock();
*last_error = Some((Instant::now(), error.to_string())); *last_error = Some((Instant::now(), error.to_string()));
let mut error_count = self.connection_error_count.lock(); self.connection_error_count.fetch_add(1, Ordering::Relaxed);
*error_count += 1;
} }
fn should_reset_clients(&self) -> bool { fn should_reset_clients(&self) -> bool {
let error_count = *self.connection_error_count.lock(); let error_count = self.connection_error_count.load(Ordering::Relaxed);
let last_error = self.last_connection_error.lock(); let last_error = self.last_connection_error.lock();
if error_count > 5 { if error_count > 5 {
@@ -120,10 +122,7 @@ impl NetworkManager {
let mut client = self.no_proxy_client.lock(); let mut client = self.no_proxy_client.lock();
*client = None; *client = None;
} }
{ self.connection_error_count.store(0, Ordering::Relaxed);
let mut error_count = self.connection_error_count.lock();
*error_count = 0;
}
} }
/// 创建带有自定义选项的HTTP请求 /// 创建带有自定义选项的HTTP请求

View File

@@ -15,10 +15,7 @@ use parking_lot::{Mutex, RwLock};
use percent_encoding::percent_decode_str; use percent_encoding::percent_decode_str;
use scopeguard; use scopeguard;
use serde_yaml::Mapping; use serde_yaml::Mapping;
use std::{ use std::time::{Duration, Instant};
sync::Arc,
time::{Duration, Instant},
};
use tauri::{AppHandle, Manager}; use tauri::{AppHandle, Manager};
use tokio::net::TcpListener; use tokio::net::TcpListener;
@@ -33,7 +30,7 @@ const DEFAULT_WIDTH: u32 = 940;
const DEFAULT_HEIGHT: u32 = 700; const DEFAULT_HEIGHT: u32 = 700;
// 添加全局UI准备就绪标志 // 添加全局UI准备就绪标志
static UI_READY: OnceCell<Arc<RwLock<bool>>> = OnceCell::new(); static UI_READY: OnceCell<RwLock<bool>> = OnceCell::new();
// 窗口创建锁,防止并发创建窗口 // 窗口创建锁,防止并发创建窗口
static WINDOW_CREATING: OnceCell<Mutex<(bool, Instant)>> = OnceCell::new(); static WINDOW_CREATING: OnceCell<Mutex<(bool, Instant)>> = OnceCell::new();
@@ -63,18 +60,18 @@ impl Default for UiReadyState {
} }
// 获取UI就绪状态细节 // 获取UI就绪状态细节
static UI_READY_STATE: OnceCell<Arc<UiReadyState>> = OnceCell::new(); static UI_READY_STATE: OnceCell<UiReadyState> = OnceCell::new();
fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> { fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> {
WINDOW_CREATING.get_or_init(|| Mutex::new((false, Instant::now()))) WINDOW_CREATING.get_or_init(|| Mutex::new((false, Instant::now())))
} }
fn get_ui_ready() -> &'static Arc<RwLock<bool>> { fn get_ui_ready() -> &'static RwLock<bool> {
UI_READY.get_or_init(|| Arc::new(RwLock::new(false))) UI_READY.get_or_init(|| RwLock::new(false))
} }
fn get_ui_ready_state() -> &'static Arc<UiReadyState> { fn get_ui_ready_state() -> &'static UiReadyState {
UI_READY_STATE.get_or_init(|| Arc::new(UiReadyState::default())) UI_READY_STATE.get_or_init(UiReadyState::default)
} }
// 更新UI准备阶段 // 更新UI准备阶段