Skip to content

Commit 2727b8c

Browse files
committed
feat: instrument agent run startup for hang diagnosis
1 parent 684009f commit 2727b8c

4 files changed

Lines changed: 41 additions & 2 deletions

File tree

packages/uipath/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath"
3-
version = "2.13.13"
3+
version = "2.13.14"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

packages/uipath/src/uipath/_cli/__init__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import faulthandler
12
import importlib.metadata
23
import os
34
import sys
@@ -9,6 +10,30 @@
910
from uipath._utils._logs import setup_logging
1011
from uipath.platform.constants import DOTENV_FILE
1112

13+
14+
def _arm_startup_traceback_watchdog() -> None:
15+
"""Dump all thread stacks to stderr if startup blocks past a threshold.
16+
17+
Armed at import time (before the lazy command modules load) so a hang
18+
in module import or runtime construction is captured in the job logs,
19+
where a stalled process is otherwise silent. Cancelled by the run
20+
command once the runtime is ready, so a healthy run never dumps.
21+
Opt-in via UIPATH_STARTUP_TRACEBACK_SECONDS; auto-enabled in the
22+
serverless runtime with a conservative default.
23+
"""
24+
raw = os.environ.get("UIPATH_STARTUP_TRACEBACK_SECONDS")
25+
if raw is None and os.environ.get("UIPATH_ENVIRONMENT_TAG") == "Serverless":
26+
raw = "120"
27+
try:
28+
seconds = int(raw) if raw else 0
29+
except ValueError:
30+
seconds = 0
31+
if seconds > 0:
32+
faulthandler.dump_traceback_later(seconds, repeat=True, file=sys.stderr)
33+
34+
35+
_arm_startup_traceback_watchdog()
36+
1237
# Windows console uses codepages (e.g. cp1252) that can't encode Unicode
1338
# characters used by Rich spinners (Braille) and emoji output.
1439
# When piped (not a TTY), keep the system encoding so the parent process

packages/uipath/src/uipath/_cli/cli_run.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import asyncio
2+
import faulthandler
3+
import logging
24
from typing import Any
35

46
import click
@@ -41,6 +43,7 @@
4143
from .middlewares import Middlewares
4244

4345
console = ConsoleLogger()
46+
logger = logging.getLogger(__name__)
4447

4548

4649
class _RunDiscoveryError(EntrypointDiscoveryException):
@@ -222,16 +225,19 @@ async def execute() -> None:
222225
factory: UiPathRuntimeFactoryProtocol | None = None
223226
governance_bootstrap: GovernanceBootstrap | None = None
224227
try:
228+
logger.info("[startup] resolving runtime factory")
225229
factory = UiPathRuntimeFactoryRegistry.get(context=ctx)
226230

227231
resolved_entrypoint = entrypoint
228232
if not resolved_entrypoint:
233+
logger.info("[startup] discovering entrypoint")
229234
available = factory.discover_entrypoints()
230235
if len(available) == 1:
231236
resolved_entrypoint = available[0]
232237
else:
233238
raise _RunDiscoveryError(available)
234239

240+
logger.info("[startup] loading factory settings")
235241
factory_settings = await factory.get_settings()
236242
trace_settings = (
237243
factory_settings.trace_settings
@@ -248,6 +254,7 @@ async def execute() -> None:
248254
if factory_settings
249255
else None
250256
)
257+
logger.info("[startup] resolving governance")
251258
governance_bootstrap = await resolve_governance(
252259
agent_framework=agent_framework,
253260
agent_type=agent_type,
@@ -262,11 +269,18 @@ async def execute() -> None:
262269
governance_bootstrap.evaluator
263270
)
264271

272+
logger.info(
273+
"[startup] building runtime and compiling graph "
274+
"(entrypoint=%s)",
275+
resolved_entrypoint,
276+
)
265277
base_runtime = await factory.new_runtime(
266278
resolved_entrypoint,
267279
governance_runtime_id,
268280
**new_runtime_kwargs,
269281
)
282+
logger.info("[startup] runtime ready, starting execution")
283+
faulthandler.cancel_dump_traceback_later()
270284

271285
if governance_bootstrap is not None:
272286
base_runtime = governance_bootstrap.wrap_runtime(

packages/uipath/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)