Skip to content

[BUG] fit_predict_async and load_data_source_async jobs stay "pending" forever — event loop created but never started #222

@harsh2025-sketch

Description

@harsh2025-sketch

Summary

fit_predict_async_tool and load_data_source_async_tool return a job_id
saying the job started. But the job never runs — it stays "pending" forever.
The problem is that both tools submit coroutines to an event loop that is never
started in a background thread.

Steps to Reproduce

import sys, time
sys.path.insert(0, "src")
from sktime_mcp.runtime.executor import get_executor

executor = get_executor()

result = executor.fit_predict_async({
    "dataset": "airline",
    "estimator": "NaiveForecaster",
    "horizon": 12
})

job_id = result["job_id"]

time.sleep(0.5)
print(executor.get_job_status({"job_id": job_id})["status"])  # pending

time.sleep(2.0)
print(executor.get_job_status({"job_id": job_id})["status"])  # still pending

What's Happening

In fit_predict.py and data_tools.py:

loop = asyncio.get_event_loop()               # gets a loop — but never runs it
asyncio.run_coroutine_threadsafe(coro, loop)  # submits to a stopped loop
                                              # coroutine sits in queue forever

run_coroutine_threadsafe only works if the loop is actively running
in another thread. There is no such thread started anywhere, so jobs never execute.

Expected vs Actual

Expected Actual
Job status after 2 seconds running / completed pending
Coroutine executes Yes Never
Async workflows usable by LLM Yes Completely broken

Suggested Fix

Add a shared background event loop thread at server startup:

# src/sktime_mcp/runtime/_background_loop.py
import asyncio, threading

class _BackgroundLoop:
    def __init__(self):
        self._loop = asyncio.new_event_loop()
        self._thread = threading.Thread(
            target=self._loop.run_forever, daemon=True
        )
        self._thread.start()

    def submit(self, coro):
        return asyncio.run_coroutine_threadsafe(coro, self._loop)

BG_LOOP = _BackgroundLoop()

Then in fit_predict.py and data_tools.py replace:

# Old broken code:
loop = asyncio.get_event_loop()
asyncio.run_coroutine_threadsafe(coro, loop)

# New working code:
from sktime_mcp.runtime._background_loop import BG_LOOP
BG_LOOP.submit(coro)

Related Issues

Environment

  • sktime-mcp: 0.1.0
  • Python: 3.12.9
  • sktime: 0.40.1
  • mcp: 1.27.0
  • OS: Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions