Skip to content

chore(asyncio): migrate remaining background-task sites to asyncio_utils#9596

Merged
mscolnick merged 2 commits into
mainfrom
ms/async-usage-2
May 20, 2026
Merged

chore(asyncio): migrate remaining background-task sites to asyncio_utils#9596
mscolnick merged 2 commits into
mainfrom
ms/async-usage-2

Conversation

@mscolnick

Copy link
Copy Markdown
Contributor

Follow-up to the asyncio hardening pass. Replaces hand-rolled task
creation and cancel-and-await patterns with the shared helpers.

  • supervised_task in lsp.py (health monitor), mcp/client.py (health
    monitor + connection lifecycle), rtc/doc.py (loro cleaner), and
    middleware.py (timeout monitor).
  • cancel_and_wait in mcp/client.py (single-server health cancel) and
    terminal.py's _cancel_tasks helper.
Follow-up to the asyncio hardening pass. Replaces hand-rolled task
creation and cancel-and-await patterns with the shared helpers.

- supervised_task in lsp.py (health monitor), mcp/client.py (health
  monitor + connection lifecycle), rtc/doc.py (loro cleaner), and
  middleware.py (timeout monitor).
- cancel_and_wait in mcp/client.py (single-server health cancel) and
  terminal.py's _cancel_tasks helper.
Copilot AI review requested due to automatic review settings May 19, 2026 02:01
@vercel

vercel Bot commented May 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment May 19, 2026 1:32pm

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 5 files

Architecture diagram
sequenceDiagram
    participant App as Application
    participant U as asyncio_utils
    participant Task as Background Task
    
    Note over App,Task: supervised_task wraps asyncio.create_task
    
    App->>U: supervised_task(coro, name="...")
    U->>U: wrap in cancellable task handle
    U->>U: attach exception logging
    U->>Task: asyncio.create_task(wrapped_coro)
    Task-->>U: Task handle
    U-->>App: Task handle
    
    Note over App,Task: cancel_and_wait replaces hand-rolled cancel+await
    
    App->>U: cancel_and_wait(task)
    U->>Task: task.cancel()
    Task-->>U: CancelledError
    U->>U: await task (suppresses CancelledError)
    U-->>App: None
    
    Note over App: Health monitor lifecycle (LSP, MCP, Timeout)
    
    App->>App: start health monitor
    App->>U: supervised_task(monitor(), name="lsp.health.{id}")
    U-->>App: health_task
    alt monitor stops normally
        health_task->>App: completes
    else monitor needs cancellation
        App->>U: cancel_and_wait(health_task)
        U-->>App: cancellation handled
    end
    
    Note over App: MCP connection lifecycle
    
    App->>U: supervised_task(connection_lifecycle(), name="mcp.lifecycle.{name}")
    U-->>App: lifecycle_task
    App->>App: discover tools
    App->>U: supervised_task(health_monitor(), name="mcp.health.{name}")
    U-->>App: health_task
    alt connection closes
        App->>U: cancel_and_wait(health_task)
        U-->>App: cancelled
    end
    
    Note over App: RTC cleaner
    
    App->>App: remove client from LoroDoc
    App->>U: supervised_task(clean_loro_doc(), name="rtc.cleaner.{file_key}")
    U-->>App: cleaner_task
    
    Note over App: Terminal task cleanup
    
    App->>U: cancel_and_wait(task) (for each task)
    U->>Task: cancel + await
    U-->>App: done
    
    Note over App: Timeout monitor
    
    App->>U: supervised_task(monitor(), name="timeout.monitor")
    U-->>App: monitor_task
Loading

Re-trigger cubic

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR continues the asyncio hardening work by migrating remaining ad-hoc background task creation/cancellation patterns to shared helpers in marimo._utils.asyncio_utils, aiming for more consistent exception logging, task naming, and cancellation handling.

Changes:

  • Replaced several asyncio.create_task(...) call sites with supervised_task(...) and added descriptive task names.
  • Replaced local “cancel + await + suppress CancelledError” loops with cancel_and_wait(...) in terminal and MCP single-server health cancellation.
  • Standardized background task handling for LSP health monitoring, RTC doc cleanup, and inactivity timeout monitoring.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
marimo/_server/rtc/doc.py Uses supervised_task for RTC loro doc cleaner tasks and names them for easier debugging/logging.
marimo/_server/lsp.py Uses supervised_task for LSP process health monitor task with a stable name.
marimo/_server/api/middleware.py Uses supervised_task for the inactivity timeout monitor task.
marimo/_server/api/endpoints/terminal.py Uses cancel_and_wait to simplify and harden task cancellation/awaiting during terminal websocket cleanup.
marimo/_server/ai/mcp/client.py Uses supervised_task for MCP health monitors and connection lifecycle tasks; uses cancel_and_wait for single-server health monitor cancellation.
Comment thread marimo/_server/ai/mcp/client.py Outdated
@mscolnick mscolnick added the bug Something isn't working label May 19, 2026
connection_task is awaited in disconnect_from_server(), so supervised_task's
done-callback would log the exception in addition to the awaiter, producing
duplicate error logs. Revert this one site to asyncio.create_task; the strong
reference is already held via connection.connection_task.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 5 files

Architecture diagram
sequenceDiagram
    participant LSP as LSP Server
    participant MCP as MCP Client
    participant RTC as RTC Doc Manager
    participant Middleware as Timeout Middleware
    participant TTY as Terminal Session
    participant AsyncUtils as asyncio_utils

    Note over LSP,AsyncUtils: Background task lifecycle migration

    LSP->>AsyncUtils: supervised_task(health_monitor(), name="lsp.health.{id}")
    AsyncUtils-->>LSP: Task handle (with error logging + cleanup)

    MCP->>AsyncUtils: supervised_task(health_monitor(), name="mcp.health.{server}")
    AsyncUtils-->>MCP: Task handle
    MCP->>MCP: _connection_lifecycle() uses asyncio.create_task (unsupervised)
    Note over MCP: Connection lifecycle task not supervised<br/>because it is awaited during disconnect

    MCP->>AsyncUtils: cancel_and_wait(health_check_tasks[server_name])
    AsyncUtils->>MCP: Cancels task, awaits CancelledError

    RTC->>AsyncUtils: supervised_task(cleaner(), name="rtc.cleaner.{key}")
    AsyncUtils-->>RTC: Task handle

    Middleware->>AsyncUtils: supervised_task(monitor(), name="timeout.monitor")
    AsyncUtils-->>Middleware: Task handle

    TTY->>AsyncUtils: cancel_and_wait(task) (per task in _cancel_tasks)
    AsyncUtils->>TTY: Cancels each task, awaits CancelledError

    alt Task fails unexpectedly
        AsyncUtils->>AsyncUtils: Log error + traceback
    end
    alt Task cancelled
        AsyncUtils->>AsyncUtils: Silently await CancelledError
    end
Loading

Re-trigger cubic

@mscolnick mscolnick requested a review from kirangadhave May 20, 2026 02:37

@kirangadhave kirangadhave left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🚀

@mscolnick mscolnick merged commit 13c3f53 into main May 20, 2026
44 checks passed
@mscolnick mscolnick deleted the ms/async-usage-2 branch May 20, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

3 participants