fix: abort connection on error preventing infinite build (#6050)
* fix: abort connection on build errors * fix: streamline error message formatting in ErrorMessage class * test: remove timeout from waitForSelector in generalBugs-shard-10.spec.ts --------- Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
parent
d676aef9b4
commit
d24e989a91
6 changed files with 643 additions and 32 deletions
|
|
@ -389,7 +389,6 @@ async def build_flow(
|
|||
raise
|
||||
event_manager.on_vertices_sorted(data={"ids": ids, "to_run": vertices_to_run})
|
||||
await client_consumed_queue.get()
|
||||
|
||||
tasks = []
|
||||
for vertex_id in ids:
|
||||
task = asyncio.create_task(build_vertices(vertex_id, graph, client_consumed_queue, event_manager))
|
||||
|
|
|
|||
|
|
@ -368,18 +368,9 @@ class MessageResponse(DefaultModel):
|
|||
class ErrorMessage(Message):
|
||||
"""A message class specifically for error messages with predefined error-specific attributes."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
exception: BaseException,
|
||||
session_id: str | None = None,
|
||||
source: Source | None = None,
|
||||
trace_name: str | None = None,
|
||||
flow_id: UUID | str | None = None,
|
||||
) -> None:
|
||||
# This is done to avoid circular imports
|
||||
if exception.__class__.__name__ == "ExceptionWithMessageError" and exception.__cause__ is not None:
|
||||
exception = exception.__cause__
|
||||
# Get the error reason
|
||||
@staticmethod
|
||||
def _format_markdown_reason(exception: BaseException) -> str:
|
||||
"""Format the error reason with markdown formatting."""
|
||||
reason = f"**{exception.__class__.__name__}**\n"
|
||||
if hasattr(exception, "body") and isinstance(exception.body, dict) and "message" in exception.body:
|
||||
reason += f" - **{exception.body.get('message')}**\n"
|
||||
|
|
@ -391,7 +382,37 @@ class ErrorMessage(Message):
|
|||
reason += f" - **Details:**\n\n```python\n{exception!s}\n```\n"
|
||||
else:
|
||||
reason += " - **An unknown error occurred.**\n"
|
||||
return reason
|
||||
|
||||
@staticmethod
|
||||
def _format_plain_reason(exception: BaseException) -> str:
|
||||
"""Format the error reason without markdown."""
|
||||
if hasattr(exception, "body") and isinstance(exception.body, dict) and "message" in exception.body:
|
||||
reason = f"{exception.body.get('message')}\n"
|
||||
elif hasattr(exception, "code"):
|
||||
reason = f"Code: {exception.code}\n"
|
||||
elif hasattr(exception, "args") and exception.args:
|
||||
reason = f"{exception.args[0]}\n"
|
||||
elif isinstance(exception, ValidationError):
|
||||
reason = f"{exception!s}\n"
|
||||
else:
|
||||
reason = "An unknown error occurred.\n"
|
||||
return reason
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
exception: BaseException,
|
||||
session_id: str | None = None,
|
||||
source: Source | None = None,
|
||||
trace_name: str | None = None,
|
||||
flow_id: UUID | str | None = None,
|
||||
) -> None:
|
||||
# This is done to avoid circular imports
|
||||
if exception.__class__.__name__ == "ExceptionWithMessageError" and exception.__cause__ is not None:
|
||||
exception = exception.__cause__
|
||||
|
||||
plain_reason = self._format_plain_reason(exception)
|
||||
markdown_reason = self._format_markdown_reason(exception)
|
||||
# Get the sender ID
|
||||
if trace_name:
|
||||
match = re.search(r"\((.*?)\)", trace_name)
|
||||
|
|
@ -402,7 +423,7 @@ class ErrorMessage(Message):
|
|||
session_id=session_id,
|
||||
sender=source.display_name if source else None,
|
||||
sender_name=source.display_name if source else None,
|
||||
text=reason,
|
||||
text=plain_reason,
|
||||
properties=Properties(
|
||||
text_color="red",
|
||||
background_color="red",
|
||||
|
|
@ -422,7 +443,7 @@ class ErrorMessage(Message):
|
|||
type="error",
|
||||
component=source.display_name if source else None,
|
||||
field=str(exception.field) if hasattr(exception, "field") else None,
|
||||
reason=reason,
|
||||
reason=markdown_reason,
|
||||
solution=str(exception.solution) if hasattr(exception, "solution") else None,
|
||||
traceback=traceback.format_exc(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -119,6 +119,11 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
false,
|
||||
);
|
||||
set({ isBuilding: false });
|
||||
get().revertBuiltStatusFromBuilding();
|
||||
get().setLockChat(false);
|
||||
useAlertStore.getState().setErrorData({
|
||||
title: "Build stopped",
|
||||
});
|
||||
},
|
||||
isPending: true,
|
||||
setHasIO: (hasIO) => {
|
||||
|
|
@ -757,14 +762,6 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
get().setLockChat(false);
|
||||
},
|
||||
onBuildUpdate: handleBuildUpdate,
|
||||
onBuildStopped: () => {
|
||||
get().setIsBuilding(false);
|
||||
setErrorData({
|
||||
title: "Build stopped",
|
||||
});
|
||||
get().revertBuiltStatusFromBuilding();
|
||||
get().setLockChat(false);
|
||||
},
|
||||
onBuildError: (title: string, list: string[], elementList) => {
|
||||
const idList =
|
||||
(elementList
|
||||
|
|
@ -783,6 +780,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
setErrorData({ list, title });
|
||||
get().setIsBuilding(false);
|
||||
get().setLockChat(false);
|
||||
get().buildController.abort();
|
||||
},
|
||||
onBuildStart: (elementList) => {
|
||||
const idList = elementList
|
||||
|
|
|
|||
|
|
@ -199,7 +199,8 @@ export async function buildFlowVertices({
|
|||
onBuildStart(ids.map((id) => ({ id: id, reference: id })));
|
||||
ids.forEach((id) => verticesStartTimeMs.set(id, Date.now()));
|
||||
};
|
||||
|
||||
console.log("type", type);
|
||||
console.log("data", data);
|
||||
switch (type) {
|
||||
case "vertices_sorted": {
|
||||
const verticesToRun = data.to_run;
|
||||
|
|
@ -319,7 +320,7 @@ export async function buildFlowVertices({
|
|||
case "error": {
|
||||
if (data?.category === "error") {
|
||||
useMessagesStore.getState().addMessage(data);
|
||||
if (data?.properties?.source?.id === null) {
|
||||
if (!data?.properties?.source?.id) {
|
||||
onBuildError!("Error Building Flow", [data.text]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ test(
|
|||
|
||||
await page.getByTestId("button_run_chat output").click();
|
||||
|
||||
await page.waitForSelector("text=built successfully", { timeout: 30000 });
|
||||
await page.waitForSelector("text=built successfully");
|
||||
|
||||
await page.getByTestId("playground-btn-flow-io").click();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue