From d1521547ef7e00c796b14e40b8219372c8122379 Mon Sep 17 00:00:00 2001 From: Michael Piatek Date: Wed, 28 Oct 2026 06:34:02 -0700 Subject: [PATCH] Raise the `databricks --version` probe timeout to 30s On a loaded arca box the dbexec-wrapped CLI can take more than 10s to answer `--version`. The timeout reads as an unparseable version, so the launch fails with "Could not parse Databricks CLI version" even though the re-probe for the error message returns a valid one. Co-authored-by: Isaac --- src/ucode/databricks.py | 14 ++++++++++++-- tests/test_databricks.py | 11 +++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/ucode/databricks.py b/src/ucode/databricks.py index 69c0267f2..7358b1cf3 100644 --- a/src/ucode/databricks.py +++ b/src/ucode/databricks.py @@ -66,6 +66,10 @@ MIN_DATABRICKS_CLI_VERSION = (1, 0, 0) # v1.11.0 fixes `fs cp` (create -> finalize), which the skills MCP uploads rely on. SKILLS_MCP_MIN_DATABRICKS_CLI_VERSION = (1, 11, 0) +# `databricks --version` is normally instant, but a wrapper binary (e.g. dbexec on +# arca) under concurrent startups can take several seconds; a timeout reads as an +# unparseable version and fails the launch. +_DATABRICKS_CLI_VERSION_TIMEOUT_SECONDS = 30 TOKEN_REFRESH_INTERVAL_SECONDS = 1800 # Substrings the Databricks CLI emits when it loses the token-cache write lock # to a concurrent `databricks auth token` (e.g. another ucode helper process @@ -789,7 +793,13 @@ def _read_databricks_cli_version(path: str) -> tuple[int, int, int] | None: place — every other caller reads a version through ``databricks_cli_path()``. """ try: - result = run([path, "--version"], check=False, capture_output=True, text=True, timeout=10) + result = run( + [path, "--version"], + check=False, + capture_output=True, + text=True, + timeout=_DATABRICKS_CLI_VERSION_TIMEOUT_SECONDS, + ) except (OSError, subprocess.TimeoutExpired): return None raw = result.stdout or result.stderr or "" @@ -980,7 +990,7 @@ def ensure_databricks_cli_version( check=False, capture_output=True, text=True, - timeout=10, + timeout=_DATABRICKS_CLI_VERSION_TIMEOUT_SECONDS, ) raw = result.stdout or result.stderr or "" output = (raw if isinstance(raw, str) else raw.decode(errors="replace")).strip() diff --git a/tests/test_databricks.py b/tests/test_databricks.py index b0efa989f..4959f9b8e 100644 --- a/tests/test_databricks.py +++ b/tests/test_databricks.py @@ -4280,6 +4280,17 @@ def boom(*a, **kw): monkeypatch.setattr(db_mod, "run", boom) assert db_mod._read_databricks_cli_version("/usr/bin/databricks") is None + def test_read_version_allows_slow_cli(self, monkeypatch): + seen = {} + + def fake_run(*a, **kw): + seen["timeout"] = kw["timeout"] + return subprocess.CompletedProcess(a, 0, "Databricks CLI v1.20.0", "") + + monkeypatch.setattr(db_mod, "run", fake_run) + db_mod._read_databricks_cli_version("/usr/bin/databricks") + assert seen["timeout"] == db_mod._DATABRICKS_CLI_VERSION_TIMEOUT_SECONDS >= 30 + def test_read_version_parses_output(self, monkeypatch): monkeypatch.setattr( db_mod,