Skip to content

refactor(git): key worker checkouts by GitBranch UID and reclaim orphans - #453

Merged
sunib merged 2 commits into
refactor-dupl-helpersfrom
refactor/worker-dir-gitbranch-uid
Oct 26, 2026
Merged

sunib merged 2 commits into
refactor-dupl-helpersfrom
refactor/worker-dir-gitbranch-uid

Conversation

@sunib

@sunib sunib commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #451.

Local clones live under /tmp/gitops-reverser-workers/{GitBranch UID} instead of /tmp/gitops-reverser-workers/{provider UID}/{branch-component}.

Why the GitBranch UID is enough

  • A GitBranch pins its branch: spec.branch is immutable.
  • The branch claim gives a repository branch to one GitBranch at a time, and EnsureWorker keeps at most one live worker per GitBranch (it removes the old one before starting a replacement, under lifecycleMu). No two live workers share a directory.
  • A UID is new for every object, so a GitBranch deleted and recreated under its name gets a new directory.
  • The branch name is no longer in the path, so branchPathComponent (which kept release/v1 from nesting inside release) goes away.

EnsureWorker reads the UID from the claim holder that it already checks, so WorkerRequest and the GitTarget reconciler are unchanged.

What changes in behavior

The repository is the one thing the GitBranch UID does not pin. A GitProvider recreated against another URL keeps the GitBranch, so the replacement worker now uses the same directory. Before, the new provider UID gave it a new directory. This is safe:

  • EnsureWorker stops the old worker and removes its clone before the replacement starts.
  • A checkout left on disk across a restart is never trusted. A new worker's base is untrusted, so its first cycle runs PrepareBranchFrom, which repoints origin and fetches and resets.

RepoIdentity.ProviderUID stays: it still detects that a provider was recreated, which triggers the replacement.

Checkouts no GitBranch names are reclaimed

A retiring worker removes its own checkout. A GitBranch deleted while no worker ran for it, across a restart that kept the disk (a container restart inside its pod), left its directory behind. ReconcileWorkers (every minute, and after every GitTarget delete) now also deletes every directory under the root that no live worker uses and no existing GitBranch names:

  • It runs under lifecycleMu, so no worker starts while it reads the directories.
  • A GitBranch whose worker has not started yet keeps its checkout.
  • A GitBranch List that fails deletes nothing.
  • Directories from the previous {provider UID}/{branch} layout are removed too.

Because the sweep deletes whatever its own cluster does not name, a test binary that runs a WorkerManager must not share the default root. SetWorkerStateRoot gives internal/git and internal/controller their own root from TestMain. Before this, TestReconcileWorkers_KeepsAWorkerASiblingStillNeeds swept the real /tmp/gitops-reverser-workers.

Persisting checkouts across pod replacement

/tmp is an emptyDir: checkouts survive a container restart, but a new pod clones every branch again. No new chart value is needed for this. The chart README shows how to mount a PersistentVolumeClaim at /tmp/gitops-reverser-workers through the existing volumes/volumeMounts values. ReadWriteOnce is enough, because the chart runs one replica and the default strategy stops the old pod first.

Tests

  • TestRepoRootPath_IsOneDirectoryPerGitBranch replaces the provider-incarnation and branch-component tests.
  • TestWorkerLifecycle_AReplacementStartsFromAnEmptyCheckout replaces the test that the predecessor's checkout and the replacement's are different directories. They are now the same directory, and the old clone is gone before the new worker starts.
  • TestReconcileWorkers_ReclaimsCheckoutsNoGitBranchNames and ..._ReclaimsNothingWhenTheGitBranchesCannotBeRead cover the sweep.
  • removeLocalState acts only for a worker with a GitBranch UID, which every manager-started worker has.
  • Test claimants get UIDs without slashes, like real UIDs, and newTestBranchWorker sets a GitBranch UID.

task lint and task test pass. Local task test-e2e passes on both commits (109 of 168 specs, the default filter). One run on the second commit died in BeforeSuite on the known audit warm-up signature after a k3d node restart; it passed after task clean-cluster.

🤖 Generated with Claude Code

Local clones move from /tmp/gitops-reverser-workers/{provider UID}/{branch-component}
to /tmp/gitops-reverser-workers/{GitBranch UID}. A GitBranch pins its branch, the
claim gives a repository branch to one GitBranch, and EnsureWorker keeps one live
worker per GitBranch, so its UID is a complete name for the checkout. The branch
name no longer appears in the path, so branchPathComponent goes.

EnsureWorker reads the UID from the claim holder it already checks. A provider
recreated against another URL keeps the GitBranch, so its replacement worker reuses
the directory after the old worker has removed the clone in it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 10 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 42ab6949-29c8-410e-b458-2ed4bbccfcfc
Commits

Reviewing files that changed from the base of the PR and between d01f25e and 0461828.

Files selected for processing: 11
  • charts/gitops-reverser/README.md
  • docs/architecture.md
  • internal/controller/git_branch_helpers_test.go
  • internal/controller/main_test.go
  • internal/git/branch_worker.go
  • internal/git/claim_helpers_test.go
  • internal/git/git_operations_test.go
  • internal/git/helpers_test.go
  • internal/git/worker_manager.go
  • internal/git/worker_manager_test.go
  • internal/watch/git_branch_helpers_test.go
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.48649% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/git/worker_manager.go 83.8% 5 Missing ⚠️

📢 Thoughts on this report? Let us know!

@sunib
sunib added this pull request to stack #452 October 26, 2026 08:50
A retiring worker removes its own checkout, but a GitBranch deleted while no
worker ran for it, across a restart that kept the disk, left its directory
behind. The worker sweep now also deletes every directory under the state root
that no live worker uses and no existing GitBranch names. It runs under
lifecycleMu, so no worker starts while it reads, and a GitBranch List that fails
deletes nothing. Checkouts from the previous {provider UID}/{branch} layout go
the same way.

Because the sweep deletes whatever its own cluster does not name, a test binary
that runs a WorkerManager must not share the default root: SetWorkerStateRoot
gives internal/git and internal/controller their own from TestMain.

The chart README shows how to keep checkouts across pod replacement by mounting
a PersistentVolumeClaim through the existing volumes/volumeMounts values.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@sunib sunib changed the title refactor(git): key a worker's checkout by its GitBranch UID refactor(git): key worker checkouts by GitBranch UID and reclaim orphans Oct 26, 2026
@sunib
sunib merged commit 8085da5 into main Oct 26, 2026
29 checks passed
@sunib
sunib deleted the refactor/worker-dir-gitbranch-uid branch October 26, 2026 09:35
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.

1 participant