aboutsummaryrefslogtreecommitdiff
path: root/src/app/mod.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-07 15:34:26 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-07 15:35:20 +0300
commitb425260f9d86bb7e0bbea1d1e557ee75ba22443e (patch)
treed67a0896bdfa5ce027fc85982d547ed995936265 /src/app/mod.rs
parentb017d212905b4de04770100ad993cb5c0b7855ca (diff)
perf: move session autosaves off main loop
Diffstat (limited to 'src/app/mod.rs')
-rw-r--r--src/app/mod.rs75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 8f33e23a..51bdd33e 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -128,6 +128,7 @@ pub struct App {
pub(crate) selection_autoscroll_deadline: Option<Instant>,
pub(crate) selection_highlight_clear_deadline: Option<Instant>,
pub(crate) session_save_deadline: Option<Instant>,
+ pub(crate) session_save_thread: Option<std::thread::JoinHandle<()>>,
pub(crate) persist_pane_history: bool,
pub(crate) last_render_at: Option<Instant>,
pub(crate) suppressed_repeat_keys:
@@ -719,6 +720,7 @@ impl App {
agent_metadata_deadline: None,
pending_agent_resume_deadline: None,
session_save_deadline: None,
+ session_save_thread: None,
selection_autoscroll_deadline: None,
selection_highlight_clear_deadline: None,
persist_pane_history: config.experimental.pane_history,
@@ -1739,6 +1741,14 @@ mod tests {
)
}
+ fn unique_temp_path(name: &str) -> std::path::PathBuf {
+ let stamp = std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .unwrap()
+ .as_nanos();
+ std::env::temp_dir().join(format!("herdr-{name}-{}-{stamp}", std::process::id()))
+ }
+
#[cfg(windows)]
fn exiting_test_command() -> &'static str {
"C:\\Windows\\System32\\whoami.exe"
@@ -4076,6 +4086,71 @@ mod tests {
}
#[test]
+ fn due_session_save_starts_background_writer() {
+ let _guard = crate::config::test_config_env_lock().lock().unwrap();
+ let config_home = unique_temp_path("background-session-save");
+ std::env::set_var("XDG_CONFIG_HOME", &config_home);
+ std::env::remove_var(crate::session::SESSION_ENV_VAR);
+
+ let mut app = test_app();
+ app.no_session = false;
+ app.state.workspaces = vec![Workspace::test_new("autosave")];
+ app.state.ensure_test_terminals();
+ app.session_save_deadline = Some(Instant::now() - Duration::from_secs(1));
+
+ app.handle_scheduled_tasks(Instant::now(), false);
+
+ assert!(app.session_save_thread.is_some());
+ assert!(app.session_save_deadline.is_none());
+ app.save_session_now();
+ assert!(crate::session::data_dir().join("session.json").exists());
+
+ std::env::remove_var("XDG_CONFIG_HOME");
+ let _ = std::fs::remove_dir_all(config_home);
+ }
+
+ #[test]
+ fn background_session_save_reschedules_when_writer_is_busy() {
+ let mut app = test_app();
+ app.no_session = false;
+ let (release_tx, release_rx) = std::sync::mpsc::channel();
+ app.session_save_thread = Some(std::thread::spawn(move || {
+ let _ = release_rx.recv();
+ }));
+
+ app.start_background_session_save();
+
+ assert!(app.session_save_thread.is_some());
+ assert!(app.session_save_deadline.is_some());
+
+ release_tx.send(()).unwrap();
+ app.no_session = true;
+ app.save_session_now();
+ }
+
+ #[test]
+ fn final_session_save_joins_background_writer_before_returning() {
+ let mut app = test_app();
+ app.no_session = true;
+ let (release_tx, release_rx) = std::sync::mpsc::channel();
+ let (done_tx, done_rx) = std::sync::mpsc::channel();
+ app.session_save_thread = Some(std::thread::spawn(move || {
+ let _ = release_rx.recv();
+ done_tx.send(()).unwrap();
+ }));
+ let releaser = std::thread::spawn(move || {
+ std::thread::sleep(Duration::from_millis(30));
+ release_tx.send(()).unwrap();
+ });
+
+ app.save_session_now();
+
+ releaser.join().unwrap();
+ done_rx.try_recv().unwrap();
+ assert!(app.session_save_thread.is_none());
+ }
+
+ #[test]
fn next_loop_deadline_includes_selection_autoscroll_deadline() {
let mut app = test_app();
let now = Instant::now();