Merge pull request #1748 from pipecat-ai/aleix/task-manager-dictionary
task manager dictionary and cleanup PipelineTask
This commit is contained in:
@@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed a `PipelineTask` issue that would cause tasks to not be cancelled if
|
||||||
|
task was cancelled from outside of Pipecat.
|
||||||
|
|
||||||
|
- Fixed a `TaskManager` that was causing dangling tasks to be reported.
|
||||||
|
|
||||||
- Fixed an issue that could cause data to be sent to the transports when they
|
- Fixed an issue that could cause data to be sent to the transports when they
|
||||||
were still not ready.
|
were still not ready.
|
||||||
|
|
||||||
|
|||||||
@@ -286,12 +286,7 @@ class PipelineTask(BaseTask):
|
|||||||
async def cancel(self):
|
async def cancel(self):
|
||||||
"""Stops the running pipeline immediately."""
|
"""Stops the running pipeline immediately."""
|
||||||
logger.debug(f"Canceling pipeline task {self}")
|
logger.debug(f"Canceling pipeline task {self}")
|
||||||
# Make sure everything is cleaned up downstream. This is sent
|
await self._cancel()
|
||||||
# out-of-band from the main streaming task which is what we want since
|
|
||||||
# we want to cancel right away.
|
|
||||||
await self._source.push_frame(CancelFrame())
|
|
||||||
# Only cancel the push task. Everything else will be cancelled in run().
|
|
||||||
await self._task_manager.cancel_task(self._process_push_task)
|
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
"""Starts and manages the pipeline execution until completion or cancellation."""
|
"""Starts and manages the pipeline execution until completion or cancellation."""
|
||||||
@@ -309,11 +304,17 @@ class PipelineTask(BaseTask):
|
|||||||
# well, because you get a CancelledError in every place you are
|
# well, because you get a CancelledError in every place you are
|
||||||
# awaiting a task.
|
# awaiting a task.
|
||||||
pass
|
pass
|
||||||
await self._cancel_tasks()
|
finally:
|
||||||
await self._cleanup(cleanup_pipeline)
|
# It's possibe that we get an asyncio.CancelledError from the
|
||||||
if self._check_dangling_tasks:
|
# outside, if so we need to make sure everything gets cancelled
|
||||||
self._print_dangling_tasks()
|
# properly.
|
||||||
self._finished = True
|
if cleanup_pipeline:
|
||||||
|
await self._cancel()
|
||||||
|
await self._cancel_tasks()
|
||||||
|
await self._cleanup(cleanup_pipeline)
|
||||||
|
if self._check_dangling_tasks:
|
||||||
|
self._print_dangling_tasks()
|
||||||
|
self._finished = True
|
||||||
|
|
||||||
async def queue_frame(self, frame: Frame):
|
async def queue_frame(self, frame: Frame):
|
||||||
"""Queue a single frame to be pushed down the pipeline.
|
"""Queue a single frame to be pushed down the pipeline.
|
||||||
@@ -336,6 +337,14 @@ class PipelineTask(BaseTask):
|
|||||||
for frame in frames:
|
for frame in frames:
|
||||||
await self.queue_frame(frame)
|
await self.queue_frame(frame)
|
||||||
|
|
||||||
|
async def _cancel(self):
|
||||||
|
# Make sure everything is cleaned up downstream. This is sent
|
||||||
|
# out-of-band from the main streaming task which is what we want since
|
||||||
|
# we want to cancel right away.
|
||||||
|
await self._source.push_frame(CancelFrame())
|
||||||
|
# Only cancel the push task. Everything else will be cancelled in run().
|
||||||
|
await self._task_manager.cancel_task(self._process_push_task)
|
||||||
|
|
||||||
async def _create_tasks(self):
|
async def _create_tasks(self):
|
||||||
self._process_up_task = self._task_manager.create_task(
|
self._process_up_task = self._task_manager.create_task(
|
||||||
self._process_up_queue(), f"{self}::_process_up_queue"
|
self._process_up_queue(), f"{self}::_process_up_queue"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Coroutine, Optional, Set
|
from typing import Coroutine, Dict, Optional, Sequence, Set
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
@@ -69,14 +69,14 @@ class BaseTaskManager(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def current_tasks(self) -> Set[asyncio.Task]:
|
def current_tasks(self) -> Sequence[asyncio.Task]:
|
||||||
"""Returns the list of currently created/registered tasks."""
|
"""Returns the list of currently created/registered tasks."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TaskManager(BaseTaskManager):
|
class TaskManager(BaseTaskManager):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._tasks: Set[asyncio.Task] = set()
|
self._tasks: Dict[str, asyncio.Task] = {}
|
||||||
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
||||||
|
|
||||||
def set_event_loop(self, loop: asyncio.AbstractEventLoop):
|
def set_event_loop(self, loop: asyncio.AbstractEventLoop):
|
||||||
@@ -179,16 +179,17 @@ class TaskManager(BaseTaskManager):
|
|||||||
finally:
|
finally:
|
||||||
self._remove_task(task)
|
self._remove_task(task)
|
||||||
|
|
||||||
def current_tasks(self) -> Set[asyncio.Task]:
|
def current_tasks(self) -> Sequence[asyncio.Task]:
|
||||||
"""Returns the list of currently created/registered tasks."""
|
"""Returns the list of currently created/registered tasks."""
|
||||||
return self._tasks
|
return list(self._tasks.values())
|
||||||
|
|
||||||
def _add_task(self, task: asyncio.Task):
|
def _add_task(self, task: asyncio.Task):
|
||||||
self._tasks.add(task)
|
name = task.get_name()
|
||||||
|
self._tasks[name] = task
|
||||||
|
|
||||||
def _remove_task(self, task: asyncio.Task):
|
def _remove_task(self, task: asyncio.Task):
|
||||||
name = task.get_name()
|
name = task.get_name()
|
||||||
try:
|
try:
|
||||||
self._tasks.remove(task)
|
del self._tasks[name]
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
logger.trace(f"{name}: unable to remove task (already removed?): {e}")
|
logger.trace(f"{name}: unable to remove task (already removed?): {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user