Skip to content

Automatically isolate breeze testing for each git worktree in a totally isolated project. - #73836

Merged
ashb merged 6 commits into
mainfrom
breeze-project-isolation
Sep 29, 2026
Merged

ashb merged 6 commits into
mainfrom
breeze-project-isolation

Conversation

@ashb

@ashb ashb commented Sep 28, 2026

Copy link
Copy Markdown
Member

A number of brreze commands supported --project-name to be able to run
multiple breeze commands in parallel (very useful when you are using git
worktrees), but there were two big gaps to this feature:

  • the Postgres volume was "global", so all breeze projects used the same volume
  • the testing commands didn't have this flag.

Adding this means can now run breeze testing core-tests --project-name $my_worktree --backend postgres safely on multiple worktrees without collision


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

  • Read the Pull Request Guidelines for more information. Note: commit author/co-author name and email in commits become permanently public when merged.
  • For fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

A number of brreze commands supported `--project-name` to be able to run
multiple breeze commands in parallel (very useful when you are using git
worktrees), but there were two big gaps to this feature:

- the Postgres volume was "global", so all breeze projects used the same volume
- the `testing` commands didn't have this flag.

Adding this means can now run `breeze testing core-tests --project-name
$my_worktree --backend postgres` safely on multiple worktrees without collision

@shahar1 shahar1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, note the failing test (might be a transient error)

Comment thread dev/breeze/src/airflow_breeze/commands/testing_commands.py

@potiuk potiuk left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will eat your disk very quickly and will use a lot of memory and resources if you do it this way. Because you will forget to run breeze down for all the worktrees.

You won't even know you have to do it. Breeze will not automatically shut down the databases and volumes it creates to save.time when bootstrapping.

The solution to it is to detect if you are i.in worktrees and register a git hook on wprktree deletion to perform complete cleeanup.

Also 'breeze down should detect multiple worktree breeze composes running and volumes being treated and add a suite of options and commands to deal with it - possibly even warn the users when they have multiple breeze composes and volumes created

@ashb

ashb commented Sep 28, 2026 •

Copy link
Copy Markdown
Member Author

@potiuk Isn't that my (as in the user's) choice? Many people don't use work trees, and you only pay this potential cost if you specify --project-name

Note: this is "allow", not "automatically make worktrees isolated".

I don't see anything related to worktree deletion in https://git-scm.com/docs/githooks. The CLI does nothing automatic to detect the current worktree. I could have three projects on the same main checkout, and that's by design.

@ashb
ashb requested a review from potiuk September 28, 2026 12:39
Comment thread dev/breeze/doc/05_test_commands.rst
@ashb ashb changed the title Allow isolated/per-project/per-worktree tests in parallel in Breeze Allow isolated/per-project tests in parallel in Breeze Sep 28, 2026
@ashb

ashb commented Sep 28, 2026

Copy link
Copy Markdown
Member Author

I'm looking at making breeze cleanup work for all projects, not just the current one.

@potiuk

potiuk commented Sep 28, 2026

Copy link
Copy Markdown
Member

I don't see anything related to worktree deletion in https://git-scm.com/docs/githooks. The CLI does nothing automatic to detect the current worktree. I could have three projects on the same main checkout, and that's by design.

The use of workflows is that they are often created and deleted on demand - claude -w for one will create one, and when you complete working on it it will ask you whether to remove it. This will lead to many un-deleted docker-composes, because during agentic sesion/testing the LLM might simply start breeze to run tests - and used might not even be awary that they should clean-up.

Breeze has been designed to handle just "several - but static set of projects" simply.

We do it in Magpie, but indeed those hooks were Claude hooks.

I think the easiest way is:

  1. record (in ~/.breeze) which worktrees (folders) breeze project runs on associate docker project with it
  2. at the start of any breeze command check if the folders still exist - and docker compose --project PROJECT down --volumes --remove-orphans for such project.

@potiuk

potiuk commented Sep 28, 2026

Copy link
Copy Markdown
Member

We could also run a reaper process for each worktree or one per all, but we do not need to delete the project immediately, it's enough that it is deleted automatically when the worktree is gone. And when the worktree is gone, there is no way running project will have any use.

@potiuk

potiuk commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

This will be way better - to automatically have a separate breeze project per each worktree, there is no particular need to specify --project manually in this case.

If you want I can quickly implement this @ashb

@ashb

ashb commented Sep 28, 2026 •

Copy link
Copy Markdown
Member Author

It's alright, I've got it @potiuk (i've got a chunk of it already written locally)

Also I think we can record the worktree as a label on the docker resources, so don't need to track things via files.

@Andrushika Andrushika left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left two comments, thanks.

Comment thread scripts/ci/docker-compose/backend-postgres.yml
Comment thread dev/breeze/doc/05_test_commands.rst

@potiuk potiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Fine how it is - since you indeed describe a manual process, and cleanup change might be useful, but I will also add a new option (configured with a new setup, enabled by default) to get separate project per worktree automatically. I think it's totally worth it - and your PR gave me this idea.

Project isolation leaves named database volumes behind after test containers
are removed. Cleanup needs a Breeze ownership marker independent of Compose
project names so those unused volumes remain discoverable across worktrees.

An absolute checkout path lets cleanup identify containers whose linked
worktree has been deleted, including running database services. Empty paths
preserve primary-checkout containers, and shared caches and networks have no
worktree owner. Filesystem errors must not be treated as evidence of deletion.
This path check assumes the Docker resources belong to the local machine.

Volume pruning follows container cleanup so it can reclaim newly unreferenced
storage while Docker preserves volumes still attached to containers. Existing
volumes retain their creation-time labels, so the legacy default-project
filter remains necessary; older custom-project volumes need manual cleanup.
When a worktree is detected, the last component of the dirname is taken
as the suffix of the project name.

And to prevent bloating of DB from deleted worktrees, any
"docker"-touching command will clean up dead resources from any deleted
worktrees.
@ashb ashb changed the title Allow isolated/per-project tests in parallel in Breeze Automatically isolate breeze testing for each git worktree in a totally isolated project. Sep 28, 2026

@potiuk potiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking this further. Using labels for ownership (org.apache.airflow.breeze / .worktree) is a nicer basis than a separate registry, and it means resources are marked for cleanup as soon as they're created.

Since my earlier approval, the PR has changed from the manual --project-name flow to automatic per-worktree naming plus an opportunistic sweep. I've left four inline comments on the new part. Two I'd like addressed before merge because they can hurt users:

  • the check=True calls in the sweep, which can fail unrelated commands
  • staleness decided by local path existence, which can remove resources that belong to another host

The other two are silent behaviour changes: the Postgres volume rename, and the scope of breeze down. The PR description also still describes only the manual flag, so it's worth updating it to cover the automatic naming and the new breeze down semantics.

Several improvements go beyond the original scope, and I'm happy to do them in a follow-up PR rather than grow this one:

  • Automatic resource release when a worktree is deleted. A small detached watcher, started on the first compose up in a worktree, brings the project down soon after the directory disappears. Today CPU and memory are only freed on the next Docker-touching breeze command.

  • A breeze setup config switch for per-worktree isolation, on by default.

  • A short path hash in the project name. Same-named worktrees in different locations or clones currently share a project.

  • Scoping the remaining fixed names:

    • the breeze-docs, breeze-db, breeze-prek, breeze-constraints* and breeze-providers* projects
    • the airflow-ctl, task-sdk and quick-start conftest projects, which are currently neither scoped nor labelled
    • the fixed container_names and the kerberos network
  • Per-worktree kind cluster names and the pycache volume, and cleaning up both.

  • A warning from breeze down (or a listing) when other worktrees' projects and volumes are still around.

  • An ADR (dev/breeze/doc/adr/0019-…) describing the whole per-worktree isolation effort:

    • why worktrees need isolation
    • label-based ownership, rather than a registry or name matching
    • the naming scheme
    • what is deliberately kept shared (CI/PROD images, the mypy cache, host ports)
    • the cleanup triggers (opportunistic sweep, watcher, explicit breeze down/cleanup) and their safety rules (host scoping, best-effort sweep)
    • the opt-out switch

    Today that reasoning lives only in commit messages and review threads.


Drafted-by: Claude Code (Opus 5.5); reviewed by @potiuk before posting

Comment thread dev/breeze/src/airflow_breeze/utils/docker_command_utils.py
Comment thread dev/breeze/src/airflow_breeze/utils/docker_command_utils.py
Comment thread scripts/ci/docker-compose/backend-postgres.yml
Comment thread dev/breeze/src/airflow_breeze/commands/developer_commands.py
@ashb
ashb force-pushed the breeze-project-isolation branch from 680fd57 to 298c46a Compare September 28, 2026 20:57
@ashb
ashb merged commit 0768924 into main Sep 29, 2026
155 of 156 checks passed
@ashb
ashb deleted the breeze-project-isolation branch September 29, 2026 09:26
@github-actions

Copy link
Copy Markdown
Contributor

Backport failed to create: v3-3-test. View the failure log Run details

Note: As of Merging PRs targeted for Airflow 3.X
the committer who merges the PR is responsible for backporting the PRs that are bug fixes (generally speaking) to the maintenance branches.

In matter of doubt please ask in #release-management Slack channel.

Status Branch Result
❌ v3-3-test Commit Link

You can attempt to backport this manually by running:

cherry_picker 0768924 v3-3-test

This should apply the commit to the v3-3-test branch and leave the commit in conflict state marking
the files that need manual conflict resolution.

After you have resolved the conflicts, you can continue the backport process by running:

cherry_picker --continue

If you don't have cherry-picker installed, see the installation guide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants