> This page is for version 0.4.0.
> For other versions, use one of these documentation indexes:
> - Main (default): https://docs.nvidia.com/nemo/gym/main/llms.txt
> - 0.7.0: https://docs.nvidia.com/nemo/gym/v0.7.0/llms.txt
> - 0.6.0: https://docs.nvidia.com/nemo/gym/v0.6.0/llms.txt
> - 0.5.1: https://docs.nvidia.com/nemo/gym/v0.5.1/llms.txt
> - 0.5.0: https://docs.nvidia.com/nemo/gym/v0.5.0/llms.txt
> - 0.4.0: https://docs.nvidia.com/nemo/gym/v0.4.0/llms.txt
> - 0.3.0: https://docs.nvidia.com/nemo/gym/v0.3.0/llms.txt
> - 0.2.1: https://docs.nvidia.com/nemo/gym/v0.2.1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/gym/llms.txt.

# nemo_gym.web.session_manager

Backend-neutral in-process web session lifecycle and concurrency control.

## Module Contents

### Classes

| Name                                                                   | Description                                                    |
| ---------------------------------------------------------------------- | -------------------------------------------------------------- |
| [`WebSessionManager`](#nemo_gym-web-session_manager-WebSessionManager) | Bind a signed Gym session cookie to one live backend instance. |
| [`_PendingCleanup`](#nemo_gym-web-session_manager-_PendingCleanup)     | -                                                              |

### Data

[`BackendFactory`](#nemo_gym-web-session_manager-BackendFactory)

[`LOG`](#nemo_gym-web-session_manager-LOG)

### API

```python
class nemo_gym.web.session_manager.WebSessionManager(
    config: nemo_gym.web.resource_config.WebResourcesServerConfig,
    backend_factory: nemo_gym.web.session_manager.BackendFactory,
    site_pool: nemo_gym.web.site_pool.SitePool | None = None,
    operation_runner: nemo_gym.web.operation_runner.WebOperationRunner | None = None,
    browser_session_provider: nemo_gym.web.browser_session.BrowserSessionProvider | None = None,
    prepare_runtime: typing.Callable[[], None] | None = None
)
```

Bind a signed Gym session cookie to one live backend instance.

**`_artifacts`**

---

**`_browser_heartbeat_failures`** `= 0`

---

**`_browser_heartbeat_task`** `Task[None] | None = None`

---

**`_browser_leases_acquired`** `= 0`

---

**`_browser_leases_released`** `= 0`

---

**`_browser_release_failures`** `= 0`

---

**`_browser_session_provider`**

---

**`_creating`** `set[str] = set()`

---

**`_failed_seed_cleanup_tasks`** `set[Task[None]] = set()`

---

**`_last_browser_provider_error`** `= ''`

---

**`_late_browser_cleanup_tasks`** `set[Task[None]] = set()`

---

**`_late_cleanup_owners`** `dict[Task[None], str] = {}`

---

**`_late_release_attempts`** `dict[int, int] = {}`

---

**`_late_release_handles`** `dict[int, BrowserSessionHandle] = {}`

---

**`_late_release_owners`** `dict[int, str] = {}`

---

**`_late_release_tasks`** `dict[int, Task[bool]] = {}`

---

**`_lock`** `= asyncio.Lock()`

---

**`_pending_cleanup`** `dict[str, _PendingCleanup] = {}`

---

**`_reaper_task`** `Task[None] | None = None`

---

**`_session_cleanup_tasks`** `dict[str, Task[bool]] = {}`

---

**`_sessions`** `dict[str, WebSessionState] = {}`

---

**`_site_pool`** `= site_pool or self._make_site_pool(config)`

---

**`_started_at`** `= time.time()`

---

```python
nemo_gym.web.session_manager.WebSessionManager._acquire_browser_lease(
    session_id: str,
    task: nemo_gym.web.models.WebTask
) -> nemo_gym.web.browser_session.BrowserSessionHandle
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._browser_heartbeat_loop() -> None
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._call_optional_provider_lifecycle(
    method_name: str
) -> None
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._cleanup_failed_seed(
    session_id: str,
    backend: nemo_gym.web.protocol.WebEnvironmentBackend | None,
    operation_runner: nemo_gym.web.operation_runner.WebOperationRunner | None,
    browser_lease: nemo_gym.web.browser_session.BrowserSessionHandle | None,
    site_lease: nemo_gym.web.site_pool.SiteLease | None
) -> None
```

async

Attempt every cleanup layer after a failed or cancelled seed.

```python
nemo_gym.web.session_manager.WebSessionManager._close_pending(
    session_id: str
) -> bool
```

async

Retain failed handles; only successful layers are forgotten.

A failed backend close must not destroy its thread-affine executor or
release site locks while the browser could still mutate that site.

```python
nemo_gym.web.session_manager.WebSessionManager._get_session(
    session_id: str
) -> nemo_gym.web.session.WebSessionState
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._has_unfinished_acquire(
    session_id: str
) -> bool
```

```python
nemo_gym.web.session_manager.WebSessionManager._make_operation_runner(
    session_id: str
) -> nemo_gym.web.operation_runner.WebOperationRunner
```

```python
nemo_gym.web.session_manager.WebSessionManager._make_site_pool(
    config: nemo_gym.web.resource_config.WebResourcesServerConfig
) -> nemo_gym.web.site_pool.SitePool
```

staticmethod

```python
nemo_gym.web.session_manager.WebSessionManager._reaper_loop() -> None
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._release_browser_lease(
    handle: nemo_gym.web.browser_session.BrowserSessionHandle,
    count_acquire: bool = False
) -> bool
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._release_browser_lease_after_cancellation(
    handle: nemo_gym.web.browser_session.BrowserSessionHandle
) -> bool
```

async

Release one lease after its parent rollout has been cancelled.

```python
nemo_gym.web.session_manager.WebSessionManager._release_late_acquire(
    acquire_task: asyncio.Task[nemo_gym.web.browser_session.BrowserSessionHandle],
    provider_name: str,
    session_id: str
) -> None
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._require_same_task(
    current: nemo_gym.web.models.WebTask,
    requested: nemo_gym.web.models.WebTask,
    session_id: str
) -> None
```

staticmethod

```python
nemo_gym.web.session_manager.WebSessionManager._require_unfenced(
    state: nemo_gym.web.session.WebSessionState
) -> None
```

staticmethod

```python
nemo_gym.web.session_manager.WebSessionManager._reset_backend(
    operation_runner: nemo_gym.web.operation_runner.WebOperationRunner,
    backend: nemo_gym.web.protocol.WebEnvironmentBackend,
    task: nemo_gym.web.models.WebTask
) -> tuple[nemo_gym.web.models.WebObservation, dict[str, typing.Any]]
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._retry_late_release(
    key: int
) -> bool
```

async

```python
nemo_gym.web.session_manager.WebSessionManager._run_backend(
    operation_runner: nemo_gym.web.operation_runner.WebOperationRunner,
    operation: typing.Callable[..., typing.Any],
    args: typing.Any = ()
) -> typing.Any
```

async

Run a backend operation on its thread-affine Playwright worker.

```python
nemo_gym.web.session_manager.WebSessionManager._schedule_late_acquire_cleanup(
    acquire_task: asyncio.Task[nemo_gym.web.browser_session.BrowserSessionHandle],
    provider_name: str,
    session_id: str
) -> None
```

Own an acquire that outlived its rollout and release any late handle.

A provider may implement `acquire` with a blocking SDK delegated to a
thread. Cancelling the awaiting coroutine cannot stop that SDK call.
Keeping the task alive closes the race between caller timeout and the
remote session becoming billable.

```python
nemo_gym.web.session_manager.WebSessionManager._seed_response(
    state: nemo_gym.web.session.WebSessionState
) -> nemo_gym.web.api_models.WebSeedSessionResponse
```

staticmethod

```python
nemo_gym.web.session_manager.WebSessionManager._validate_task(
    task: nemo_gym.web.models.WebTask
) -> None
```

```python
nemo_gym.web.session_manager.WebSessionManager.can_retry_seed(
    session_id: str
) -> bool
```

async

A failed seed can run again only after its cleanup has finished.

```python
nemo_gym.web.session_manager.WebSessionManager.close_session(
    session_id: str
) -> bool
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.evaluate(
    session_id: str,
    final_answer: str | None = None
) -> nemo_gym.web.api_models.WebEvaluateResponse
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.health() -> dict[str, typing.Any]
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.is_live_session(
    session_id: str
) -> bool
```

async

Check ownership without refreshing the session's idle timer.

```python
nemo_gym.web.session_manager.WebSessionManager.observe(
    session_id: str
) -> nemo_gym.web.models.WebObservation
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.recording_artifacts(
    session_id: str
) -> list[nemo_gym.web.models.WebArtifactRef]
```

async

Index recordings only after browser close has flushed them to disk.

```python
nemo_gym.web.session_manager.WebSessionManager.reset_session(
    session_id: str,
    body: nemo_gym.web.api_models.WebResetRequest
) -> nemo_gym.web.api_models.WebSeedSessionResponse
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.seed_session(
    session_id: str,
    body: nemo_gym.web.api_models.WebSeedSessionRequest
) -> nemo_gym.web.api_models.WebSeedSessionResponse
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.session_status(
    session_id: str
) -> nemo_gym.web.api_models.WebSessionStatusResponse
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.start() -> None
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.step(
    session_id: str,
    body: nemo_gym.web.api_models.WebStepRequest
) -> nemo_gym.web.api_models.WebStepResponse
```

async

```python
nemo_gym.web.session_manager.WebSessionManager.stop() -> None
```

async

```python
class nemo_gym.web.session_manager._PendingCleanup(
    backend: nemo_gym.web.protocol.WebEnvironmentBackend | None,
    runner: nemo_gym.web.operation_runner.WebOperationRunner | None,
    browser: nemo_gym.web.browser_session.BrowserSessionHandle | None,
    site: nemo_gym.web.site_pool.SiteLease | None,
    lock: asyncio.Lock,
    healthy: bool,
    attempts: int = 0
)
```

Dataclass

**`attempts`** `int = 0`

---

**`backend`** `WebEnvironmentBackend | None`

---

**`browser`** `BrowserSessionHandle | None`

---

**`healthy`** `bool`

---

**`lock`** `Lock`

---

**`runner`** `WebOperationRunner | None`

---

**`site`** `SiteLease | None`

---

```python
nemo_gym.web.session_manager.BackendFactory = Callable[[WebResourcesServerConfig, str, WebArtifactStore, BrowserSessionHandle]...
```

```python
nemo_gym.web.session_manager.LOG = logging.getLogger('nemo_gym.web.session_manager')
```