pipeline(task): process ErrorFrame in same task and stop pipeline task

This commit is contained in:
Aleix Conchillo Flaqué
2024-08-15 15:22:40 -07:00
parent 66670a2370
commit 981269d594
2 changed files with 24 additions and 10 deletions

View File

@@ -239,7 +239,7 @@ class CancelFrame(SystemFrame):
class ErrorFrame(SystemFrame): class ErrorFrame(SystemFrame):
"""This is used notify upstream that an error has occurred downstream the """This is used notify upstream that an error has occurred downstream the
pipeline.""" pipeline."""
error: str | None error: str
def __str__(self): def __str__(self):
return f"{self.name}(error: {self.error})" return f"{self.name}(error: {self.error})"
@@ -247,9 +247,9 @@ class ErrorFrame(SystemFrame):
@dataclass @dataclass
class StopTaskFrame(SystemFrame): class StopTaskFrame(SystemFrame):
"""Indicates that a pipeline task should be stopped. This should inform the """Indicates that a pipeline task should be stopped but that the pipeline
pipeline processors that they should stop pushing frames but that they processors should be kept in a running state. This is normally queued from
should be kept in a running state. the pipeline task.
""" """
pass pass

View File

@@ -10,7 +10,14 @@ from typing import AsyncIterable, Iterable
from pydantic import BaseModel from pydantic import BaseModel
from pipecat.frames.frames import CancelFrame, EndFrame, ErrorFrame, Frame, MetricsFrame, StartFrame, StopTaskFrame from pipecat.frames.frames import (
CancelFrame,
EndFrame,
ErrorFrame,
Frame,
MetricsFrame,
StartFrame,
StopTaskFrame)
from pipecat.pipeline.base_pipeline import BasePipeline from pipecat.pipeline.base_pipeline import BasePipeline
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.utils.utils import obj_count, obj_id from pipecat.utils.utils import obj_count, obj_id
@@ -37,10 +44,18 @@ class Source(FrameProcessor):
match direction: match direction:
case FrameDirection.UPSTREAM: case FrameDirection.UPSTREAM:
await self._up_queue.put(frame) await self._handle_upstream_frame(frame)
case FrameDirection.DOWNSTREAM: case FrameDirection.DOWNSTREAM:
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
async def _handle_upstream_frame(self, frame: Frame):
if isinstance(frame, ErrorFrame):
logger.error(f"Error running app: {frame.error}")
# Cancel all tasks downstream.
await self.push_frame(CancelFrame())
# Tell the task we should stop.
await self._up_queue.put(StopTaskFrame())
class PipelineTask: class PipelineTask:
@@ -70,7 +85,7 @@ class PipelineTask:
# Make sure everything is cleaned up downstream. This is sent # Make sure everything is cleaned up downstream. This is sent
# out-of-band from the main streaming task which is what we want since # out-of-band from the main streaming task which is what we want since
# we want to cancel right away. # we want to cancel right away.
await self._source.process_frame(CancelFrame(), FrameDirection.DOWNSTREAM) await self._source.push_frame(CancelFrame())
self._process_down_task.cancel() self._process_down_task.cancel()
self._process_up_task.cancel() self._process_up_task.cancel()
await self._process_down_task await self._process_down_task
@@ -134,9 +149,8 @@ class PipelineTask:
while True: while True:
try: try:
frame = await self._up_queue.get() frame = await self._up_queue.get()
if isinstance(frame, ErrorFrame): if isinstance(frame, StopTaskFrame):
logger.error(f"Error running app: {frame.error}") await self.queue_frame(StopTaskFrame())
await self.queue_frame(CancelFrame())
self._up_queue.task_done() self._up_queue.task_done()
except asyncio.CancelledError: except asyncio.CancelledError:
break break