Skip to content

Fix: Panic 'no reactor running' in verified_lists background refresh#121

Open
sentry[bot] wants to merge 1 commit into
mainfrom
seer/fix/async-verified-lists-commands
Open

Fix: Panic 'no reactor running' in verified_lists background refresh#121
sentry[bot] wants to merge 1 commit into
mainfrom
seer/fix/async-verified-lists-commands

Conversation

@sentry

@sentry sentry Bot commented Jun 26, 2026

Copy link
Copy Markdown

Summary

This PR resolves a panic (there is no reactor running, must be called from the context of a Tokio 1.x runtime) that occurred when synchronous Tauri commands invoked corkscrew_lib::verified_lists::maybe_refresh_in_background.

The root cause was that synchronous Tauri commands execute on a blocking thread pool, which lacks the necessary Tokio runtime context for tauri::async_runtime::spawn to function correctly. Although tauri::async_runtime::spawn is designed to be runtime-agnostic, its underlying implementation (delegating to tokio::task::spawn in Tauri 2) still requires an active Tokio reactor.

Changes

  • Converted the three affected Tauri commands (get_collection_verification, get_wabbajack_verification, and get_verification_manifest) from pub fn to pub async fn. This ensures they are executed on Tauri's internal Tokio runtime, providing the required reactor context for maybe_refresh_in_background to safely spawn its background refresh task.
  • Updated the code comment in verified_lists.rs regarding the safety of tauri::async_runtime::spawn for clarity.

Testing

  • cargo test -p corkscrew passes
  • npx svelte-check --threshold error passes
  • Manually tested with cargo tauri dev (if UI changes)

Fixes RUST-B

Greptile Summary

Converts three synchronous Tauri commands (get_collection_verification, get_wabbajack_verification, get_verification_manifest) to async fn so that maybe_refresh_in_background's internal tauri::async_runtime::spawn call has a live Tokio reactor, eliminating the "no reactor running" panic. The companion comment in verified_lists.rs is updated to accurately document this constraint.

  • The three commands do not .await any work themselves; async is used solely to opt into Tauri's runtime thread pool rather than the blocking pool.
  • get_verification_cache_age_secs (which does not call maybe_refresh_in_background) is correctly left as pub fn.
  • The updated comment in verified_lists.rs now clearly warns that maybe_refresh_in_background must only be called from an async context.

Confidence Score: 4/5

Safe to merge — the fix correctly eliminates the runtime panic and the only remaining concern is a minor blocking I/O call that now runs on an async thread.

The root-cause analysis is sound and the change is minimal and targeted. The one thing to keep in mind is that ensure_initialized() can do a synchronous std::fs::read on the first command invocation; this was previously safe on Tauri's blocking thread pool but now executes on an async worker thread. The file is small and initialization is one-shot, so it won't cause problems in practice, but it's worth tracking for a future cleanup.

src-tauri/src/commands/verified_lists_cmds.rs — the blocking disk I/O path in ensure_initialized is now reachable from an async worker thread for the first time.

Important Files Changed

Filename Overview
src-tauri/src/commands/verified_lists_cmds.rs Three commands converted from pub fn to pub async fn to provide a Tokio runtime context for maybe_refresh_in_background; the three affected commands do not .await anything themselves, so async is used purely for runtime context. A minor concern exists: ensure_initialized() may do blocking disk I/O on the first call, which now runs on an async worker thread rather than Tauri's blocking pool.
src-tauri/src/verified_lists.rs Comment on maybe_refresh_in_background updated to accurately reflect that callers must be async and that calling from a sync command would panic; no logic changes.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Frontend
    participant TauriRuntime as Tauri Async Runtime
    participant Cmd as verified_lists_cmds (async fn)
    participant VL as verified_lists
    participant BG as Background Refresh Task

    Frontend->>TauriRuntime: invoke("get_collection_verification")
    TauriRuntime->>Cmd: dispatch on async worker thread
    Cmd->>VL: maybe_refresh_in_background()
    VL->>VL: ensure_initialized() / check TTL
    alt cache stale or missing
        VL->>TauriRuntime: tauri::async_runtime::spawn(refresh_from_remote)
        TauriRuntime-->>BG: spawned (fire-and-forget)
    end
    Cmd->>VL: collection_status(game_domain, slug)
    VL-->>Cmd: VerifiedEntry
    Cmd-->>Frontend: VerifiedEntry (returns immediately with cached data)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Frontend
    participant TauriRuntime as Tauri Async Runtime
    participant Cmd as verified_lists_cmds (async fn)
    participant VL as verified_lists
    participant BG as Background Refresh Task

    Frontend->>TauriRuntime: invoke("get_collection_verification")
    TauriRuntime->>Cmd: dispatch on async worker thread
    Cmd->>VL: maybe_refresh_in_background()
    VL->>VL: ensure_initialized() / check TTL
    alt cache stale or missing
        VL->>TauriRuntime: tauri::async_runtime::spawn(refresh_from_remote)
        TauriRuntime-->>BG: spawned (fire-and-forget)
    end
    Cmd->>VL: collection_status(game_domain, slug)
    VL-->>Cmd: VerifiedEntry
    Cmd-->>Frontend: VerifiedEntry (returns immediately with cached data)
Loading

Fix All in Claude Code

Reviews (1): Last reviewed commit: "Fix: Panic 'no reactor running' in verif..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Comment on lines +6 to 21
pub async fn get_collection_verification(game_domain: String, slug: String) -> VerifiedEntry {
verified_lists::maybe_refresh_in_background();
verified_lists::collection_status(&game_domain, &slug)
}

#[tauri::command]
pub fn get_wabbajack_verification(modlist_name: String) -> VerifiedEntry {
pub async fn get_wabbajack_verification(modlist_name: String) -> VerifiedEntry {
verified_lists::maybe_refresh_in_background();
verified_lists::wabbajack_status(&modlist_name)
}

#[tauri::command]
pub fn get_verification_manifest() -> Manifest {
pub async fn get_verification_manifest() -> Manifest {
verified_lists::maybe_refresh_in_background();
verified_lists::full_manifest()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Blocking I/O on async worker thread on first call

maybe_refresh_in_background() calls ensure_initialized(), which on its first invocation falls through to load_disk_cache()std::fs::read(...). Previously, as pub fn commands, these ran on Tauri's blocking thread pool where synchronous I/O is explicitly allowed. As pub async fn, they run on Tokio's async worker threads, and a blocking std::fs::read there will stall a worker thread for the duration of the read. The disk file is small and initialization only happens once per process, so the practical risk is low — but the correct long-term fix would be to use tokio::fs::read inside an async ensure_initialized (or call the existing sync path via tokio::task::spawn_blocking).

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants