Skip to content

[python] Reclaim test pipelines a killed CI run leaves running - #6801

Merged
gz merged 3 commits into
mainfrom
ci-reclaim-leaked-test-pipelines
Aug 4, 2026
Merged

[python] Reclaim test pipelines a killed CI run leaves running#6801
gz merged 3 commits into
mainfrom
ci-reclaim-leaked-test-pipelines

Conversation

@gz

@gz gz commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Pipelines from the runtime suites keep running on the shared CI instance long after their run ends, consuming compute until the daily cleanup job stops them. Names like adc8e_test_uda, 17eca_negative_tests2_617224c4 and 532f6_jsonbench-default accumulate across many commits.

Why they survive

Teardown only runs while pytest is alive. Cancelling the workflow run, evicting a runner or timing out a job kills it outright, and every pipeline in flight survives. ci.yml's cancel sentinels make this routine: any sibling job failing cancels the whole run, killing the runtime tests mid-test on both matrix legs. jsonbench leaking despite a correct finally is the clearest evidence.

Three defects made teardown fail on its own as well:

Defect Where Effect
Unbounded stop/clear wait every caller passed timeout_s=None into the SDK's while True poll one wedged pipeline hung teardown until the runner killed the job, leaking all the rest
Cleanup abandoned on first error shared_test_pipeline.py, platform/helper.py, aggtst_base.py each did stop-then-clear with no guard a transient error on stop skipped the clear that followed
Untracked pipelines new_pipeline_with_suffix (10 call sites in test_checkpoint_sync.py) cleaned only when the test reached its happy path

Changes

  • python/tests/stop_ci_run_pipelines.py, wired into test-integration-runtime.yml as an if: always() step. Matches the prefix unique_pipeline_name stamps, so it only ever touches its own run. It stops and clears storage but never deletes, so a failed run stays readable; the daily job deletes afterwards.
  • feldera.testutils.reclaim_pipeline() — one definition of reclaiming a pipeline safely: each wait bounded at 60 s, every step attempted even when the previous raised, failures returned rather than thrown. Used by all four cleanup paths.
  • SharedTestPipeline tracks every pipeline it builds, so new_pipeline_with_suffix results are torn down too.
  • Cleanup failures warn rather than fail a test. A slow stop says nothing about what the test asserted, and reset_pipeline runs before a test as well as after, where a previous run's leftover would have failed an unrelated test.

Not addressed: test_tpch.py and test_now.py call stop() outside a try, so a failure there leaks a large pipeline until the sweep runs at the end of the job. Fixing in place needs a ~150-line re-indent; the sweep bounds the damage.

Checklist

  • Unit tests added/updated
  • Integration tests added/updated
  • Documentation updated
  • Changelog updated

Breaking Changes?

No.

Pipelines from the runtime suites keep running on the shared CI instance
long after their run ends, consuming compute until the daily cleanup job
stops them.

Teardown only runs while pytest is alive. Cancelling the workflow run,
evicting a runner or timing out a job kills it outright, and every
pipeline in flight survives. A new 'if: always()' step sweeps up what
such a run left behind, matching the name prefix unique_pipeline_name
stamps on every test pipeline so it only ever touches its own run. It
stops and clears storage but never deletes, so a failed run stays
readable.

Three defects made teardown fail on its own as well:

- Every stop and clear waited without a timeout, so one wedged pipeline
  hung teardown until the runner killed the job, leaking all the rest.
  reclaim_pipeline() now bounds each wait.
- stop() raising skipped the clear that followed it. Every step now runs
  regardless, since a pipeline that never reports Stopped can still
  release its storage.
- Pipelines from new_pipeline_with_suffix() were in no teardown at all.
  SharedTestPipeline now tracks everything it builds.

Cleanup failures warn rather than fail a test: a slow stop says nothing
about what the test asserted, and the sweep reports anything genuinely
left running.

Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>
@gz
gz requested a review from mihaibudiu August 4, 2026 16:46
Comment thread python/tests/stop_ci_run_pipelines.py Outdated
Comment thread python/tests/stop_ci_run_pipelines.py
Comment thread python/tests/unit/test_reclaim_pipeline.py Outdated
gz added 2 commits August 4, 2026 10:31
Review feedback: ci_run_prefix() wrapped one call for one call site, so the call site names the prefix itself. warn() now says why it prints a workflow command under Actions and plain text elsewhere: ::warning:: reaches the run's annotation summary, and nothing reads it outside a run.

Drop tests/unit/test_reclaim_pipeline.py. It drove a mocked client and mostly restated the two functions it covered.

Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>
tests/platform/helper.py built its Authorization header from FELDERA_API_KEY, read once when the module was imported. The CI auth step exports a GitHub ID token under that name and the token expires well inside a suite, so every raw request issued after that got a 401. test_adaptive_joins waits through two compilations before it reads circuit_json_profile, which is where it failed.

The header now comes from feldera_bearer_token(), which resolves the same credential the SDK client uses and re-mints an ID token shortly before it expires. That function replaces _feldera_credential(): both spelled out the same precedence, and what is left to decide is whether a caller wants the resolver or its result. The client gets the resolver under Actions, where the token can lapse between requests.

A 401 also made reset_pipeline() return before it stopped anything, so a suite that ran past the expiry left its pipelines on the shared instance.

Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>
@gz
gz enabled auto-merge August 4, 2026 17:46
@gz
gz added this pull request to the merge queue Aug 4, 2026
Merged via the queue into main with commit 16d5c57 Aug 4, 2026
1 check passed
@gz
gz deleted the ci-reclaim-leaked-test-pipelines branch August 4, 2026 18:48
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.

2 participants