Skip to content

acc: Destroy leaked bundles after cloud test runs - #6092

Open
denik wants to merge 10 commits into
mainfrom
denik/bundle_cleaner
Open

acc: Destroy leaked bundles after cloud test runs#6092
denik wants to merge 10 commits into
mainfrom
denik/bundle_cleaner

Conversation

@denik

@denik denik commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Why

Cloud acceptance tests deploy bundles under the shared test workspace's ~/.bundle directory. Tests that crash before their cleanup trap fires leak their deployments, which accumulate and eventually exhaust the workspace child-node limit.

Changes

A suite-level cleanup runs after all tests finish and destroys every bundle this run deployed, keyed off the "cix" prefix that ciUniqueName embeds into $UNIQUE_NAME (synthesizing a run id for non-CI cloud runs). It sweeps only this run's deployments, so it is safe while other runs deploy concurrently. Local runs are unaffected — each gets its own in-memory fake workspace.

Tests

Verified on gcp-cli: a bundle deployed without a destroy step is found and destroyed by the cleanup.

@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: e3bdcf2

Run: 30540743963

Env 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 4 4 322 1066 7:21
💚​ aws windows 4 4 324 1064 5:18
💚​ azure linux 4 4 322 1065 6:44
💚​ azure windows 4 4 324 1063 5:09
💚​ gcp linux 1 5 321 1067 7:01
💚​ gcp windows 1 5 323 1065 6:15
8 interesting tests: 4 RECOVERED, 4 SKIP
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R
Top 3 slowest tests (at least 2 minutes):
duration env testname
3:08 gcp windows TestAccept
3:05 azure windows TestAccept
3:04 aws windows TestAccept

@denik
denik enabled auto-merge July 29, 2026 09:38
@denik
denik disabled auto-merge July 29, 2026 09:38
@denik

denik commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

This is not good 4cdb54c because in integration tests we use RUN_ID as prefix, so we cleaner can affect other jobs within the same run, fixing.

denik added 4 commits July 29, 2026 15:21
Cloud acceptance tests deploy bundles under the shared test workspace's
~/.bundle directory. Tests that crash before their cleanup trap fires leak
their deployments, which accumulate and eventually hit the workspace
child-node limit.

Add a suite-level cleanup that runs after all tests finish and destroys every
bundle deployed by this run. It keys off the "ci<runid>x" prefix that
ciUniqueName already embeds into $UNIQUE_NAME (synthesizing a run id for
non-CI cloud runs), so it sweeps only this run's deployments and is safe to
run while other runs deploy concurrently. Local runs are unaffected: each gets
its own in-memory fake workspace.

Co-authored-by: Isaac
Move the cloud check to the caller and compute the sweepable run id once in
testAccept instead of mutating GITHUB_RUN_ID in the environment: use the GitHub
run id on CI, otherwise a random numeric id so a local cloud run is still
sweepable. Off cloud the id is empty and ciUniqueName leaves names unchanged.

Co-authored-by: Isaac
All matrix legs of a CI run share one GITHUB_RUN_ID, and legs of different OSes
share a workspace, so a run-id-only prefix let one leg's end-of-run cleanup
destroy another still-running leg's bundles. Append a random 3-char
lowercase-alphanumeric suffix (per test process) to the ci<runid>x prefix so
each leg sweeps only its own deployments. The run id stays a matchable
substring, so the run-wide sweeper (sweep_test_resources.py) is unaffected.

Verified on gcp-cli: cleanup destroyed 2/2 of this leg's leaked bundles,
matching only names carrying its suffix.

Co-authored-by: Isaac
Each destroy shells out to a separate `bundle destroy` (auth + state pull +
deletes), so a sequential sweep of a full run's leaks takes minutes. Run them
with a WaitGroup and a semaphore capped at min(GOMAXPROCS, 20), which stays
well under the workspace API rate limit while cutting wall-clock. Best-effort
semantics are unchanged: failures are collected and reported at the end.

Co-authored-by: Isaac
@denik
denik force-pushed the denik/bundle_cleaner branch from 4920656 to 9e1f8b9 Compare July 29, 2026 13:22
denik added 6 commits July 29, 2026 22:36
Collapse randomBundleLegSuffix, bundleNamePrefix, and the run-id/suffix
splitting inside ciUniqueName into one generator (newBundleNamePrefix) that
returns the full "ci<runID>x<suffix>" string, leaving ciUniqueName as a plain
length-preserving prepend. One package var instead of two.

Co-authored-by: Isaac
From an adversarial review:
- Fail the cleanup on a non-not-found workspace listing error instead of
  treating it as an empty directory, which would silently under-sweep and leak.
- Also sweep /Shared/<user>/.bundle, where a few cloud tests set root_path
  (e.g. resources/jobs/shared-root-path), not just the home .bundle.
- Cap the accepted run id at 12 digits so an over-long GITHUB_RUN_ID can't
  build a prefix that ciUniqueName silently drops.

Co-authored-by: Isaac
From a second adversarial review:
- A "/Shared/..." root_path is normalized to "/Workspace/Shared/..." by
  prependWorkspacePrefix, so sweep that path, not "/Shared/..." (which would
  404 and miss the leak).
- Widen the per-leg suffix to 4 random chars (36^4) and cap the run id at 11
  digits so it still leaves the 8-char random minimum, making an accidental
  collision between sibling legs sharing a workspace negligible.

Co-authored-by: Isaac
ciUniqueName previously returned the name unchanged when the prefix left fewer
than 8 random characters, which silently disabled cleanup tagging. Since
newBundleNamePrefix guarantees the prefix is short enough (empty prefix off
cloud trivially fits), a too-long prefix is a programming error: panic with a
descriptive message instead of papering over it.

Co-authored-by: Isaac
From an Opus cross-check review:
- The destroys are network-bound (auth + state pull + API deletes), not
  CPU-bound, so cap concurrency at a fixed 20 instead of min(GOMAXPROCS, 20),
  which throttled to 2-4 on typical CI runners and lost most of the speedup.
- Build the local temp databricks.yml path with filepath.Join, not path.Join,
  since the dir comes from os.MkdirTemp.

Co-authored-by: Isaac
The cleanup runs in a t.Cleanup on the root TestAccept, so a require failure
there marks the root test failed with no failed subtest — which makes
gotestsum --rerun-fails (used by the integration task) rerun the entire cloud
suite. Cleanup is best-effort housekeeping and the product tests already
passed, so log a loud WARNING on every failure path (client/user resolution,
listing, destroy) instead of failing. Leaked deployments are reclaimed by the
periodic prefix sweep.

Co-authored-by: Isaac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants