Publish DBR Scala 2.13 image when a runtime ships two Scala variants - #25
Conversation
*Why*
dbr_meta read the Scala version with a single re.search, taking only the first
version a page lists. A runtime mid-migration publishes two images from one page
("Scala: 2.12.15 or 2.13.10"), but only the 2.12 folder was generated -- so a
cluster on the Scala 2.13 image (spark_version 16.4.x-scala2.13) resolves to no
published environment and 404s. This is the largest E_ENV_UNSUPPORTED source in
the VPEX telemetry (~69%: 16.4.x-scala2.13 + its cpu-ml variant), across many
distinct workspaces. DBR 16.4 LTS is the only dual-image line today; the fix is
version-agnostic so future ones are covered automatically.
*What*
- sync.py: add dbr_scalas(), which returns every Scala MAJOR.MINOR a page's System
environment lists (one entry for a single-image page, both for a dual-image one),
de-duped and in page order, with a fallback to the prior single-match. dbr_meta
returns that list; sync_dbr and the ML path write one folder per Scala version off
the shared "Installed Python libraries" table (only the Java/Scala tables split per
image, which this repo doesn't consume).
- envgen.py: extend DROP_BY_ENV with the three 16.4.x...scala2.13 keys. The pandas
1.5.x-on-cp312 problem (issue #18) is Scala-independent, so the 2.13 image needs the
same drop as the 2.12 image -- without it the new folders re-break #18.
- Regenerated artifacts: dbr/16.4.x-scala2.13, 16.4.x-cpu-ml-scala2.13,
16.4.x-gpu-ml-scala2.13. Byte-identical pin sets to their 2.12 siblings; all three
pass full `uv sync`.
- Tests: new test_sync.py (dbr_scalas/dbr_meta on dual/single/missing/malformed
input); extend the envgen pandas-drop test to the scala2.13 envs.
Co-authored-by: Isaac <no-reply@databricks.com>
Review hardening: dbr_scalas captured the raw HTML between 'Scala</strong>:' and </li>, so a version-like number inside a tag (e.g. an href to a Spark-version doc page) could be read as a Scala version and spawn a nonexistent environment. Strip inline tags first -- the same treatment table_pkgs already applies -- so only the visible version tokens count. No generated artifact changes (real pages carry no such tag digits today); adds a regression test. Co-authored-by: Isaac <no-reply@databricks.com>
…variant Review follow-up. The previous parser read every version-like token in the Scala field, so a trailing visible annotation (e.g. "2.12.15 or 2.13.10 (Apache Spark 3.5)") would add a bogus "3.5" and generate a nonexistent scala3.5 environment. Match only the leading "VER (or VER)*" enumeration -- the Scala version, or the two joined by "or" for a dual-image release -- and stop at any following text. Tag stripping is kept so the enumeration survives the "<strong>or</strong>" markup. Adds a regression test for the trailing-annotation case; no generated artifact changes. Also update README: the DBR sync description now notes that a dual-image release produces one environment per Scala version off the page's single Python table. Co-authored-by: Isaac <no-reply@databricks.com>
anton-107
left a comment
There was a problem hiding this comment.
Approving — the fix is well-scoped, correctly diagnosed, and deliberately version-agnostic, and the parser design (anchored re.match on the tag-stripped field + inner findall) is genuinely robust against the trailing-annotation and in-href number cases. Two HIGH-severity items I'd like to see addressed (they don't block merge, but the first one is important):
1. dbr_scalas only recognizes or as the separator — any other delimiter silently regresses to the original bug
The enumeration group is (?:\s+or\s+\d+\.\d+(?:\.\d+)?)*. If a runtime page ever renders the two versions with a comma (2.12.15, 2.13.10), a slash (2.12.15 / 2.13.10), and, or an HTML entity (2.12.15 or 2.13.10 — tag stripping removes <…> but leaves intact, so \s+or\s+ won't match), then re.match still matches the leading 2.12.15, the or group matches zero times, and the function returns ["2.12"] only.
That is not a failure path: scalas is truthy, so dbr_meta returns, one folder is written, and the scala2.13 env silently goes missing again — which is exactly the E_ENV_UNSUPPORTED / 404 failure this PR exists to fix. The </li> fallback doesn't protect against this because the field did match. In effect the fix is one Databricks copy-edit away from silently resurrecting the bug on a single variant.
Suggested: widen the separator (e.g. [\s,/]+(?:or|and)?[\s,/]+, or split the field directly on a version regex) and normalize → space before matching. Add tests for comma / slash / separators.
2. No end-to-end test that 16.4.x-scala2.13 actually resolves to the generated folder
The PR convincingly proves the folder is generated, but the stated goal is killing the 404 — and the resolver that maps spark_version = 16.4.x-scala2.13 to a published env isn't in this diff. Worth either a test or a manual confirmation noted on the PR that a cluster on the 2.13 image now resolves to the new env rather than 404ing, so we know the actual user-facing symptom is gone.
Findings from an automated (Claude) review pass; sharing the two highest-severity ones. Happy to file the lower-severity notes (e.g. per-Scala DROP_BY_ENV duplication, missing write-loop integration test) as follow-ups if useful.
Review follow-up (Anton, PR #25). The enumeration only accepted " or " between the two Scala versions, so a page rendered with a comma, slash, "and", or a nbsp-joined "or" would match just the leading version and return ["2.12"] -- silently dropping the 2.13 variant and re-introducing the E_ENV_UNSUPPORTED / 404 this fix exists to prevent (not a failure path: the single result is truthy, so a folder is still written). Unescape HTML entities after tag-stripping (so a nbsp entity becomes real whitespace that \s matches) and widen the inter-version delimiter to whitespace / "," / "/" / the words "or"|"and". The delimiter class still never contains a version, so the leading enumeration stops at a trailing annotation ("(Apache Spark 3.5)") as before. Adds regression tests for comma / slash / "and" / nbsp separators and a comma-plus-annotation case. No generated artifact changes. Co-authored-by: Isaac <no-reply@databricks.com>
|
Thanks @anton-107 — great catch on #1, that's a real latent regression. #1 (separator robustness) — fixed in 4c02340. The enumeration now unescapes HTML entities after tag-stripping (so an #2 (end-to-end resolve) — out of this repo's scope, confirmed manually. The resolver that maps Also happy to take your lower-severity notes (per-Scala |
Why
dbr_metaread the Scala version with a singlere.search, taking only the first version a runtime page lists. A runtime mid-migration publishes two images from one page (Scala: 2.12.15 or 2.13.10), but only the 2.12 folder was generated — so a cluster on the Scala 2.13 image (spark_version = 16.4.x-scala2.13) resolves to no published environment and 404s.This is the largest
E_ENV_UNSUPPORTEDsource in the VPEX telemetry (~69%:16.4.x-scala2.13+ itscpu-mlvariant), spread across many distinct workspaces. DBR 16.4 LTS is the only dual-image line today; the fix is version-agnostic so any future dual-image runtime is covered automatically.What
sync.py— adddbr_scalas(), returning every ScalaMAJOR.MINORa page's System environment lists (one entry for a single-image page, both for a dual-image one), de-duped and in page order, with a fallback to the prior single-match if the field isn't</li>-delimited.dbr_metareturns that list;sync_dbrand the ML path write one folder per Scala version off the sharedinstalled-python-librariestable (only the Java/Scala tables split per image, which this repo doesn't consume).envgen.py— extendDROP_BY_ENVwith the three16.4.x…scala2.13keys. Thepandas 1.5.x-on-cp312 problem (dbr/16.4.x, serverless-v3: pandas 1.5.3 can't be installed on Python 3.12 (no cp312 wheel) #18) is Scala-independent, so the 2.13 image needs the same drop as the 2.12 image — without it the new folders would re-break dbr/16.4.x, serverless-v3: pandas 1.5.3 can't be installed on Python 3.12 (no cp312 wheel) #18.dbr/16.4.x-scala2.13,dbr/16.4.x-cpu-ml-scala2.13,dbr/16.4.x-gpu-ml-scala2.13. Pin sets are byte-identical to their 2.12 siblings (only the name strings differ).test_sync.py(dbr_scalas/dbr_metaon dual/single/missing/malformed input); extend theenvgenpandas-drop test to the scala2.13 envs.Verification
python -m unittest test_sync test_envgen→ 22 passing (CI'stest.ymlauto-discoverstest_sync.py).python .github/scripts/sync.py --check→ "no changes — repo is in sync with published docs", exit 0.uv sync(build + install) PASSES for all three new envs via the Databricks PyPI proxy.This pull request and its description were written by Isaac.