Skip to content

[Bug]: First-Run Setup Progress Messages Don't Show Parallelism #7

Description

@aayushch

Description

Issue: First-Run Setup Progress Messages Don't Show Parallelism

Priority: Low (cosmetic only — no functional impact)
Component: ui/src-tauri/src/runtime.rs, ui/src-tauri/src/lib.rs

Problem

The first-run setup downloads Python, Node.js, and uv in parallel threads (via mpsc::channel in ensure_runtimes()), but the UI progress messages make it appear serial. The user sees:

"Downloading Python 3.12.13"
"Downloaded 5 MB / 28 MB"
"Downloaded 15 MB / 28 MB"
"Python 3.12.13 ready"
"Downloading Node.js 22.22.3"     ← appears to start only after Python finishes
"Downloaded 5 MB / 45 MB"
...

Similarly, steps 3 (deps) and 4 (n8n) run in parallel but the user may not notice since uv makes deps finish quickly.

Root Cause

RuntimeProgress::Bytes { downloaded, total } has no label identifying which download it belongs to. All three downloads' messages feed into a single "Preparing runtimes" step. When Python finishes before Node sends many messages (Python is ~28 MB vs Node ~45 MB), messages appear sequential.

The Bytes events can also cause the displayed download counter to jump backward (Python: 25 MB → Node: 5 MB) since each thread tracks its own downloaded counter independently.

Confirmed: Downloads ARE Parallel

The actual downloads run in separate std::thread::spawn threads and overlap on the network. Wall-clock time IS reduced. This is purely a UI visibility issue.

Proposed Fix

In ensure_runtimes(), wrap each thread's callback to convert Bytes into labeled Phase messages:

// In the python thread:
provision_python(&mut |p| {
    let labeled = match p {
        RuntimeProgress::Bytes { downloaded, total } => {
            let mb = downloaded / 1_048_576;
            RuntimeProgress::Phase(match total {
                Some(t) if t > 0 => format!("Python: {} / {} MB", mb, t / 1_048_576),
                _ => format!("Python: {} MB", mb),
            })
        }
        other => other,
    };
    let _ = tx.send(labeled);
});
// Same pattern for Node ("Node: X / Y MB") and uv ("uv: X / Y MB")

This makes interleaving visible without changing the RuntimeProgress enum or any other code. The user would see alternating "Python: 15 / 28 MB" and "Node: 10 / 45 MB" messages.

Files to Change

  • ui/src-tauri/src/runtime.rs — wrap thread callbacks in ensure_runtimes()

Steps to Reproduce

  1. Perform "first setup" run on Laya
  2. The first-run setup downloads Python, Node.js, and uv in parallel threads (via mpsc::channel in ensure_runtimes()), but the UI progress messages make it appear serial. The user sees:
"Downloading Python 3.12.13"
"Downloaded 5 MB / 28 MB"
"Downloaded 15 MB / 28 MB"
"Python 3.12.13 ready"
"Downloading Node.js 22.22.3"     ← appears to start only after Python finishes
"Downloaded 5 MB / 45 MB"
...

Expected Behavior

The progress should be linear and not jump between parallel download statuses.

Actual Behavior

The first-run setup downloads Python, Node.js, and uv in parallel threads (via mpsc::channel in ensure_runtimes()), but the UI progress messages make it appear serial. The user sees:

Component

UI (Svelte frontend)

Laya Version

No response

Operating System

None

Logs / Screenshots

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions