✨ feat(task): add TaskManagerFactory class to create and configure a TaskManager
🐛 fix(task): update get_task_status function in TaskManager class to return the correct task status 🔧 chore(task): add AsyncIOTaskResult class to handle asyncio tasks and get their status and result 🔧 chore(task): add get_celery_worker_status function to get the status of the Celery worker
This commit is contained in:
parent
5c258d08f0
commit
8faad70917
4 changed files with 116 additions and 0 deletions
0
src/backend/langflow/services/task/__init__.py
Normal file
0
src/backend/langflow/services/task/__init__.py
Normal file
11
src/backend/langflow/services/task/factory.py
Normal file
11
src/backend/langflow/services/task/factory.py
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
from langflow.services.task.manager import TaskManager
|
||||||
|
from langflow.services.factory import ServiceFactory
|
||||||
|
|
||||||
|
|
||||||
|
class TaskManagerFactory(ServiceFactory):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(TaskManager)
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
# Here you would have logic to create and configure a TaskManager
|
||||||
|
return TaskManager()
|
||||||
70
src/backend/langflow/services/task/manager.py
Normal file
70
src/backend/langflow/services/task/manager.py
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import asyncio
|
||||||
|
from typing import Any, Callable, Union
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from langflow.services.base import Service
|
||||||
|
from langflow.services.task.utils import AsyncIOTaskResult, get_celery_worker_status
|
||||||
|
|
||||||
|
try:
|
||||||
|
from celery.result import AsyncResult
|
||||||
|
from langflow.worker import celery_app
|
||||||
|
|
||||||
|
try:
|
||||||
|
status = get_celery_worker_status(celery_app)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"An error occurred: {e}")
|
||||||
|
status = {"availability": None}
|
||||||
|
USE_CELERY = status.get("availability") is not None
|
||||||
|
except ImportError:
|
||||||
|
USE_CELERY = False
|
||||||
|
|
||||||
|
|
||||||
|
class TaskManager(Service):
|
||||||
|
STATUS_PENDING = "PENDING"
|
||||||
|
STATUS_FINISHED = "FINISHED"
|
||||||
|
STATUS_UNKNOWN = "UNKNOWN"
|
||||||
|
name = "task_manager"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.tasks = {} # For storing asyncio tasks
|
||||||
|
self.celery_results = {} # For storing Celery AsyncResult instances
|
||||||
|
if USE_CELERY:
|
||||||
|
from langflow.worker import celery_app
|
||||||
|
|
||||||
|
self.celery_app = celery_app
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.celery_app = None # To store the celery app if available
|
||||||
|
self.use_celery = USE_CELERY
|
||||||
|
|
||||||
|
def launch_task(
|
||||||
|
self,
|
||||||
|
task_func: Callable[..., Any],
|
||||||
|
*args: Any,
|
||||||
|
**kwargs: Any,
|
||||||
|
) -> Union[int, str]:
|
||||||
|
if USE_CELERY:
|
||||||
|
task = task_func.apply_async(args=args, kwargs=kwargs)
|
||||||
|
self.celery_results[task.id] = task
|
||||||
|
return task.id
|
||||||
|
else:
|
||||||
|
task = asyncio.create_task(task_func(*args, **kwargs))
|
||||||
|
task_id = str(id(task))
|
||||||
|
self.tasks[task_id] = AsyncIOTaskResult(task)
|
||||||
|
|
||||||
|
def set_result(future):
|
||||||
|
try:
|
||||||
|
self.tasks[task_id] = AsyncIOTaskResult(future)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"An error occurred: {e}")
|
||||||
|
|
||||||
|
task.add_done_callback(set_result)
|
||||||
|
return task_id
|
||||||
|
|
||||||
|
# Update the get_task_status function in TaskManager class
|
||||||
|
def get_task(
|
||||||
|
self, task_id: Union[int, str]
|
||||||
|
) -> Union[AsyncResult, AsyncIOTaskResult]:
|
||||||
|
if self.use_celery:
|
||||||
|
return AsyncResult(task_id, app=self.celery_app)
|
||||||
|
return self.tasks.get(task_id)
|
||||||
35
src/backend/langflow/services/task/utils.py
Normal file
35
src/backend/langflow/services/task/utils.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
from asyncio import Task
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncIOTaskResult:
|
||||||
|
def __init__(self, task: Task):
|
||||||
|
self._task = task
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self) -> str:
|
||||||
|
if self._task.done():
|
||||||
|
return "FAILURE" if self._task.exception() is not None else "SUCCESS"
|
||||||
|
return "PENDING"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def result(self) -> any:
|
||||||
|
return self._task.result() if self._task.done() else None
|
||||||
|
|
||||||
|
def ready(self) -> bool:
|
||||||
|
return self._task.done()
|
||||||
|
|
||||||
|
|
||||||
|
def get_celery_worker_status(app):
|
||||||
|
i = app.control.inspect()
|
||||||
|
availability = i.ping()
|
||||||
|
stats = i.stats()
|
||||||
|
registered_tasks = i.registered()
|
||||||
|
active_tasks = i.active()
|
||||||
|
scheduled_tasks = i.scheduled()
|
||||||
|
return {
|
||||||
|
"availability": availability,
|
||||||
|
"stats": stats,
|
||||||
|
"registered_tasks": registered_tasks,
|
||||||
|
"active_tasks": active_tasks,
|
||||||
|
"scheduled_tasks": scheduled_tasks,
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue