From ffed6b27e9c7cc346c4b40adb6e8cf0a25844bca Mon Sep 17 00:00:00 2001 From: funman300 Date: Sun, 17 May 2026 20:58:51 -0700 Subject: [PATCH] perf(engine): share Tokio runtime across all network tasks (M-16) Replace per-call new_current_thread() runtimes with a single TokioRuntimeResource(Arc) built once at startup using new_multi_thread(worker_threads(2)). The Arc is cloned cheaply into each AsyncComputeTaskPool closure, eliminating repeated OS thread allocation on every sync pull/push, auth, avatar fetch, and analytics flush. Using a multi-threaded runtime ensures concurrent block_on calls from different worker threads are safe. Co-Authored-By: Claude Sonnet 4.6 --- solitaire_engine/src/analytics_plugin.rs | 24 +++++------- solitaire_engine/src/avatar_plugin.rs | 33 ++++++++-------- solitaire_engine/src/resources.rs | 25 ++++++++++++ solitaire_engine/src/sync_plugin.rs | 47 +++++++---------------- solitaire_engine/src/sync_setup_plugin.rs | 43 ++++++++++----------- 5 files changed, 85 insertions(+), 87 deletions(-) diff --git a/solitaire_engine/src/analytics_plugin.rs b/solitaire_engine/src/analytics_plugin.rs index 2eed279..e7f6c07 100644 --- a/solitaire_engine/src/analytics_plugin.rs +++ b/solitaire_engine/src/analytics_plugin.rs @@ -12,7 +12,7 @@ use solitaire_core::game_state::GameMode; use solitaire_data::{matomo_client::MatomoClient, settings::SyncBackend, Settings}; use crate::events::{AchievementUnlockedEvent, ForfeitEvent, GameWonEvent, NewGameRequestEvent}; -use crate::resources::GameStateResource; +use crate::resources::{GameStateResource, TokioRuntimeResource}; use crate::settings_plugin::{SettingsChangedEvent, SettingsResource}; // --------------------------------------------------------------------------- @@ -45,6 +45,7 @@ pub struct AnalyticsPlugin; impl Plugin for AnalyticsPlugin { fn build(&self, app: &mut App) { app.init_resource::() + .init_resource::() .add_systems(Startup, init_analytics) .add_systems( Update, @@ -80,28 +81,28 @@ fn react_to_settings_change( fn on_game_won( mut wins: MessageReader, analytics: Res, - settings: Res, + rt: Res, ) { let Some(client) = analytics.client.clone() else { return; }; for ev in wins.read() { client.event("Game", "Won", None, Some(ev.score as f64)); - fire_flush(client.clone(), &settings.0); + fire_flush(client.clone(), rt.0.clone()); } } fn on_forfeit( mut forfeits: MessageReader, analytics: Res, - settings: Res, + rt: Res, ) { let Some(client) = analytics.client.clone() else { return; }; for _ev in forfeits.read() { client.event("Game", "Forfeit", None, None); - fire_flush(client.clone(), &settings.0); + fire_flush(client.clone(), rt.0.clone()); } } @@ -137,14 +138,14 @@ fn on_achievement_unlocked( fn tick_flush_timer( time: Res