[SKY-8569] Fix task_v2 workflow runs missing HAR and browser console log artifacts (#5252)

This commit is contained in:
LawyZheng 2026-03-27 01:09:17 +08:00 committed by GitHub
parent 7241bdf1fc
commit 78e35dfdec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 31 additions and 0 deletions

View file

@ -4182,6 +4182,7 @@ class AgentDB(BaseAlchemyDB):
select(WorkflowRunModel)
.filter(WorkflowRunModel.organization_id == organization_id)
.filter(WorkflowRunModel.parent_workflow_run_id == parent_workflow_run_id)
.order_by(WorkflowRunModel.created_at.asc()) # intentional: clean_up_workflow uses tasks[-1]
)
workflow_runs = (await session.scalars(query)).all()
return [convert_to_workflow_run(run) for run in workflow_runs]

View file

@ -4108,6 +4108,26 @@ class WorkflowService:
) -> None:
analytics.capture("skyvern-oss-agent-workflow-status", {"status": workflow_run.status})
tasks = await self.get_tasks_by_workflow_run_id(workflow_run.workflow_run_id)
# Look up child workflow runs (e.g. from task_v2 blocks) to flatten their
# tasks into the parent list for debug artifact persistence, and collect
# child workflow_run IDs so cleanup_for_workflow_run can pop their orphaned
# entries from self.pages (child skips clean_up_workflow).
child_workflow_runs = await app.DATABASE.get_workflow_runs_by_parent_workflow_run_id(
parent_workflow_run_id=workflow_run.workflow_run_id,
organization_id=workflow_run.organization_id,
)
child_workflow_run_ids = [cwr.workflow_run_id for cwr in child_workflow_runs]
if child_workflow_runs:
LOG.info(
"Found child workflow runs for cleanup",
parent_workflow_run_id=workflow_run.workflow_run_id,
child_count=len(child_workflow_run_ids),
)
for child_run in child_workflow_runs:
child_tasks = await self.get_tasks_by_workflow_run_id(child_run.workflow_run_id)
tasks.extend(child_tasks)
all_workflow_task_ids = [task.task_id for task in tasks]
close_browser_on_completion = (
close_browser_on_completion and browser_session_id is None and not workflow_run.browser_address
@ -4118,6 +4138,7 @@ class WorkflowService:
close_browser_on_completion=close_browser_on_completion,
browser_session_id=browser_session_id,
organization_id=workflow_run.organization_id,
child_workflow_run_ids=child_workflow_run_ids,
)
if browser_state:
await self.persist_video_data(browser_state, workflow, workflow_run)

View file

@ -40,6 +40,7 @@ class BrowserManager(Protocol):
close_browser_on_completion: bool = True,
browser_session_id: str | None = None,
organization_id: str | None = None,
child_workflow_run_ids: list[str] | None = None,
) -> BrowserState | None: ...
async def get_or_create_for_script(

View file

@ -390,10 +390,18 @@ class RealBrowserManager(BrowserManager):
close_browser_on_completion: bool = True,
browser_session_id: str | None = None,
organization_id: str | None = None,
child_workflow_run_ids: list[str] | None = None,
) -> BrowserState | None:
LOG.info("Cleaning up for workflow run")
browser_state_to_close = self.pages.get(workflow_run_id)
# Pop child workflow_run entries first — these are orphaned because child
# workflows skip clean_up_workflow. Must happen before the shared check
# so the task loop can correctly detect when the browser is no longer shared.
if child_workflow_run_ids:
for child_id in child_workflow_run_ids:
self.pages.pop(child_id, None)
from skyvern.forge.sdk.routes.streaming.registries import set_deferred_close_params, stream_ref_active
streams_active = stream_ref_active(workflow_run_id)