Skip to content

[WSLC] [Per-app session support] Support multiple concurrent sessions per user on the state-aware surface #1460

Description

Migrated from ADO 64133563 (parent deliverable ADO 63911124 — [WSLC] Improvements to WSLC in MXC > 1.0). Paths below are updated to the current tree layout.

Description of the new feature / enhancement

Let the state-aware WSLc daemon hold more than one WSLc session at a time for a single user. Today it holds exactly one, and that single-session design is the root cause of two separate user-visible problems.

Current behavior. The per-user daemon boots one shared session and creates every sandbox's container inside it. ensure_session() (src/mxc-sdk/src/bin/wslc_daemon/session_manager.rs:843) is idempotent against a single session: Option<WslcSessionGuard> field (:819), with a fixed session name (SESSION_NAME = "mxc-wslc-daemon", :55) and a fixed store (%TEMP%\mxc-wslc-sessions, from default_storage_path() at :81). Sharing one warm VM across sandboxes is the deliberate amortization that the state-aware surface exists for; the cost is everything below.

Symptom 1 — session settings cannot be expressed per sandbox. cpuCount, memoryMb, gpu and storagePath are available on the one-shot surface but absent from the exact 0.9.0-alpha state-aware provision contract, which is deny_unknown_fields, so supplying any of them fails with malformed_request: unknown field, expected one of image, imageTarPath, portMappings.

They configure the session, so under one shared session only the first provision could apply them and every later sandbox would silently inherit the first caller's choice. Rejecting them is correct given the current design, but it leaves state-aware unable to size its sandboxes at all: create_daemon_session calls none of the optional WslcSetSessionSettings* entry points, so every state-aware sandbox runs on the SDK defaults of 2 CPUs and 2000 MB.

Symptom 2 — two live sessions cannot share one store. A second session opened against a store another live session already holds fails with WslcListSessionImages failed: HRESULT 0x80070020 (ERROR_SHARING_VIOLATION).

This is a property of the store, not of either surface: two concurrent one-shot runs collide the same way when both use the default store. It is most visible across surfaces, because the state-aware daemon and the one-shot runner share the same default (%TEMP%\mxc-wslc-sessions), so while any state-aware sandbox is provisioned every one-shot run on that store fails until the daemon idles out. A one-shot caller can work around it with experimental.wslc.storagePath; state-aware has no such field. Any multi-session design must give each session its own store, so this constraint is on the critical path for this item rather than a separate problem.

This is not an SDK limitation. Verified against WSLc SDK 2.9.3:

  • The API reference documents no session-count restriction. WslcCreateSession lists only two restrictions: a non-null out-parameter, and COM initialized on the calling thread.
  • Two concurrent sessions for the same user were run to completion successfully (two wxc-exec one-shot processes with overlapping lifetimes), each with its own storagePath.
  • A probe confirmed that one process, on one apartment-affine MTA thread, can hold two live session handles simultaneously and release both cleanly. This is the specific arrangement a multi-session daemon needs, and it works.

Proposed technical implementation details

What the change involves.

  • session_manager.rs — replace the single session: Option<WslcSessionGuard> with a keyed collection, and key the containers map by session as well as sandbox_id. ensure_session() becomes a lookup-or-create against that key.
  • Decide the session key. Candidates: the requested sizing tuple (sandboxes asking for the same shape share a VM), or one session per sandbox (simplest semantics, no amortization). This is the substantive design decision in this item.
  • Give each session its own store, derived per session key. Required, not optional — it is the same ERROR_SHARING_VIOLATION constraint as Symptom 2.
  • Extend the state-aware provision contract with whichever of the four fields the chosen key supports, and regenerate the schema and SDK oracles.
  • Session lifetime and the idle watchdog become per-session rather than per-daemon.

Note on gpu specifically. It is the least tractable of the four. The one-shot runner sets it in two places from the same config field: WslcSetSessionSettingsFeatureFlags(WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU) on the session, and WSLC_CONTAINER_FLAG_ENABLE_GPU on the container. The container half is per-sandbox and poses no problem; the session half is fixed when the session is created, so gpu cannot vary between sandboxes that share a session under any keying scheme. Either the key includes gpu (GPU and non-GPU sandboxes land in different VMs), or gpu stays unsupported on the state-aware surface.

Costs to weigh. Each session is a WSL2 VM, so N sessions is N VMs at 2 CPU / 2000 MB each by default. Images live in the store, so N stores means N copies of every image and N pre-pulls; scripts/setup-wslc.ps1 currently targets a single path and would need to follow. If the key is per-sandbox, the warm-reuse benefit that motivates the state-aware surface disappears.

SDK session defaults (from the WSLc SDK API reference, WslcInitSessionSettings): CPU count 2, memory 2000 MB, boot timeout 300,000 ms, VHD size ~1 GB, no feature flags, no termination callback.

Documented. The single-session limitation and the pinned store are recorded under Known limitations in docs/backends/wslc/wslc-state-aware.md.

Related. #1042 added portMappings to the state-aware provision surface. That was possible precisely because port forwards are per-container (WslcSetContainerSettingsPortMappings on the container settings object), whereas the four fields above are per-session. The per-container/per-session split is the line this item is about moving.

Activity

  1. added
    OS-WindowsApplies specifically to Windows hosts or Windows behavior.
    Backend-WSLCWindows WSL Container backend behavior or integration.
    Priority1Critical customer, security, or reliability impact requiring immediate attention.
    on Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Backend-WSLCWindows WSL Container backend behavior or integration.Issue-FeatureA request for new or expanded product functionality.Needs-TriageHas not yet been reviewed, classified, and routed.OS-WindowsApplies specifically to Windows hosts or Windows behavior.Priority1Critical customer, security, or reliability impact requiring immediate attention.

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions