Skip to content

Lifecycle

Experimental Containers Reviewed 2026-10-02 purview-dev/containers Star on GitHub 3 azurite containers csharp docker dotnet integration-testing mysql nats nuget postgresql rabbitmq redis sql-server testcontainers testing windows wsl wsl-containers wslc

Experimental. This project is an experiment: the public API, defaults and packaging can change between prereleases, and there is no production support guarantee.

Container lifecycle semantics for Purview.Containers.

public interface IContainer : IAsyncDisposable
{
Task StartAsync(CancellationToken ct = default);
Task StopAsync(CancellationToken ct = default);
ValueTask DisposeAsync();
// restart is intentionally NOT offered (WSLC has no restart; stop+start is not equivalent)
}

WSLC ContainerState: Invalid → Created → Running → Exited → Deleted.

OperationBehaviour
StartAsyncCreates the session if needed, ensures image (per pull policy), CreateContainer, then Container.Start(). A missing init binary throws ArgumentException 0x80070057 with the OCI message → surfaced as WslContainerStartupException.
StopAsyncContainer.Stop(SIGTERM, grace) then, if still running, Stop(SIGKILL, ...). Idempotent — WSLC accepts stopping an already-stopped container.
DeleteAsyncContainer.Delete(Force). Double-delete throws 0x80010108 (RPC_E_DISCONNECTED) → swallowed.
DisposeAsyncStop (if running) → Delete → release the WinRT container object. Idempotent.
  • DisposeAsync runs in finally by callers, and the container object is also registered for cleanup by the runtime so disposal happens even if a test throws after StartAsync.
  • EnableAutoRemove defaults to false: the library owns deletion via DisposeAsync. WSLC auto-removal would delete one-shot containers before their state/output could be inspected. Opt in with .WithAutoRemove() when desired.
  • Partial startup failure (image pull / create / start / wait): the container is torn down via the same DisposeAsync path.
  • Cancellation: a cancelled StartAsync/wait triggers the same teardown.
  • Container crash: InitProcess.Exited fires; the container is then in Exited state and DisposeAsync deletes it.
  • Session termination (crash): the session Terminated event marks the runtime session as dead; subsequent container operations throw a clear WslContainerSessionTerminatedException.
  • Test-process termination: a process-exit hook disposes the shared session (frees the name). Crashed processes leave an orphaned session that only reserves its name; sweep with wslc --session <name> system session terminate.
  • Container names are generated uniquely ({service}-{processId}-{random8}); never contain credentials.
  • Session names are wslc-{pid}-{random8}.
  • Diagnostics redact secrets via a Secret wrapper (ToString() returns <redacted>).