jlcodes99/cockpit-tools · warning · std::io::Error

Interrupted

Interrupted

Error message

系统正在关闭,已取消启动 {}

What it means

acquire_process_spawn_guard serializes process spawning across the app and refuses to hand out a spawn guard once application shutdown has begun (a shutdown flag checked via process_spawn_allowed/is_shutdown_started). It returns an io::Error of kind Interrupted carrying the cancelled program name. This prevents child processes from being launched while the app is tearing down.

Source

Thrown at src-tauri/src/modules/app_lifecycle.rs:36

pub fn is_shutdown_started() -> bool {
    SHUTDOWN_STARTED.load(Ordering::SeqCst)
}

pub fn begin_shutdown() -> bool {
    let _spawn_guard = lock_process_spawn();
    !SHUTDOWN_STARTED.swap(true, Ordering::SeqCst)
}

#[cfg(target_os = "windows")]
fn cancel_system_shutdown() {
    let _spawn_guard = lock_process_spawn();
    SHUTDOWN_STARTED.store(false, Ordering::SeqCst);
}

pub fn acquire_process_spawn_guard(program: &str) -> std::io::Result<ProcessSpawnGuard> {
    let guard = lock_process_spawn();
    if !process_spawn_allowed(is_shutdown_started()) {
        return Err(Error::new(
            ErrorKind::Interrupted,
            format!("系统正在关闭,已取消启动 {}", program),
        ));
    }
    Ok(ProcessSpawnGuard { _guard: guard })
}

#[cfg(target_os = "windows")]
pub fn install_system_shutdown_listener() -> Result<(), String> {
    use std::sync::mpsc::sync_channel;

    let (shutdown_tx, shutdown_rx) = sync_channel::<()>(1);
    std::thread::Builder::new()
        .name("cockpit-system-shutdown-cleanup".to_string())
        .spawn(move || {
            if shutdown_rx.recv().is_ok() {
                crate::modules::logger::log_info(
                    "[Lifecycle] Windows 正在关闭,停止后台注入并禁止创建新子进程",

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Treat this error as an expected cancellation: stop the operation and do not retry while shutdown is in progress.
  2. Check the shutdown-started flag before initiating any process launch, and subscribe to the shutdown signal to cancel pending launches.
  3. If the spawn must complete, restructure so the launch happens before shutdown begins, or persist the work and resume on next startup.
  4. If this occurs during normal operation (not shutdown), verify no code path incorrectly sets the shutdown flag early.

Example fix

// before
let guard = acquire_process_spawn_guard("powershell")?;
run_probe(guard);

// after
if is_shutdown_started() {
    return Ok(()); // skip probe during shutdown
}
let guard = match acquire_process_spawn_guard("powershell") {
    Ok(g) => g,
    Err(e) if e.kind() == std::io::ErrorKind::Interrupted => return Ok(()),
    Err(e) => return Err(e),
};
run_probe(guard);
Defensive patterns

Strategy: fallback

Validate before calling

if is_shutdown_started() {
    // skip launching; app is shutting down
    return Ok(());
}

Try / catch

match acquire_process_spawn_guard("prog") {
    Err(e) if e.kind() == std::io::ErrorKind::Interrupted => Ok(()), // cancelled by shutdown
    other => other,
}

Prevention

When it happens

Trigger: Calling acquire_process_spawn_guard (directly or via any code path that launches a child process) after SHUTDOWN_STARTED has been set — e.g. a background task or async job still trying to spawn PowerShell/other programs while the Tauri app is exiting.

Common situations: Background workers, timers, or queued tasks that outlive the shutdown signal and race with app close; long-running operations initiated just before the user quits the application.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/be1ed5255debaa9e. Report an issue: GitHub.