Skip to content

fix(git): bound protobuf git-sync memory (shallow clone) + allow disabling refresh (#2521) [backport release-2.8]#2522

Merged
c-julin merged 1 commit into
release-2.8from
cherry-pick/git-sync-memory-release-2.8
Jun 22, 2026
Merged

fix(git): bound protobuf git-sync memory (shallow clone) + allow disabling refresh (#2521) [backport release-2.8]#2522
c-julin merged 1 commit into
release-2.8from
cherry-pick/git-sync-memory-release-2.8

Conversation

@c-julin

@c-julin c-julin commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Backport of #2521 onto release-2.8.

Cherry-picks 935e3ac0e (fix(git): bound protobuf git-sync memory (shallow clone) + allow disabling refresh). Adapted to the 2.8 codebase, which still uses zap (not slog) for logging.

What it does

  • Shallow git-sync clone: CloneRepository now uses SingleBranch + Depth 1 + NoTags, so only the tip snapshot is materialized in go-git's in-memory object store instead of full repo history. Production heap profiling showed ~6.2 GB held by MemoryObject.Write under CloneRepository for a large monorepo; this bounds it to roughly one checkout.
  • Refresh by re-clone: SyncRepo re-clones the shallow snapshot on each tick instead of tree.Pull(), releasing the previous in-memory store for GC and avoiding go-git's unreliable shallow-pull. CloneRepository already updates the file cache and fires OnFilesUpdatedHook; on failure the last good cache is retained.
  • Allow disabling refresh: refreshInterval: 0 (or negative) is now permitted and disables periodic refresh (clone once at startup). Removed the Validate() rejection of 0; SyncRepo guards with <= 0. Default remains 1m, so behavior is unchanged unless 0 is set explicitly.

Backport notes

  • Logging calls kept as zap.Error(err) / zap.String(...) to match 2.8 (upstream used slog).
  • Dropped the now-unused errors import from service.go.
  • go build, go vet, and go test ./pkg/git/... pass.

…bling refresh (#2521)

* fix(git): shallow-clone protobuf git-sync to bound in-memory usage

Console clones the configured Git repository into go-git's in-memory
object store to read protobuf schema files. The clone had no depth limit,
so the entire repository history was materialized (decompressed and
un-deltified) in RAM, and the periodic refresh used an incremental
tree.Pull() that kept appending every newly fetched object to the same
never-pruned store.

For a large, active monorepo this is catastrophic: heap profiling of a
production Console pod showed ~6.2 GB (92.75% of the heap) held by
go-git's MemoryObject.Write under CloneRepository. The target repo packs
to ~600 MB on disk but inflates to ~8.5 GB across full history, growing
~0.5 GB/month, eventually OOM-killing the node.

Console only ever reads the current revision of the tracked files, so:

- Clone shallowly: SingleBranch + Depth 1 + NoTags. Fetches just the tip
  snapshot instead of the full history.
- Refresh by re-cloning instead of pulling. A fresh shallow clone keeps
  the in-memory store bounded to a single revision (the previous store is
  released for GC) and avoids go-git's unreliable shallow-pull behavior.
  CloneRepository already refreshes the file cache and fires
  OnFilesUpdatedHook; on failure the last good cache is retained.

This cuts the footprint from multiple GB to roughly one checkout and makes
it insensitive to repository history growth.

* feat(git): allow refreshInterval 0 to disable periodic refresh

Console proto schemas change rarely, so a frequent git refresh is often
unnecessary and — now that each refresh is a shallow re-clone — wasteful
on bandwidth. Operators may legitimately want "clone once at startup,
refresh only on restart", but Validate() rejected refreshInterval: 0 even
though SyncRepo already treated 0 as disabled (and the sample config
documented 0 as the way to disable it).

Allow it:
- config: drop the Validate() rejection of RefreshInterval == 0; document
  on the field that 0 disables periodic refresh (clone once at startup).
- service: guard SyncRepo with <= 0 instead of == 0 so a negative value
  also disables sync and can't panic time.NewTicker; make the log generic.

Default remains 1m, so behavior is unchanged unless 0 is set explicitly.
@c-julin c-julin merged commit 5bb9faa into release-2.8 Jun 22, 2026
3 of 5 checks passed
@c-julin c-julin deleted the cherry-pick/git-sync-memory-release-2.8 branch June 22, 2026 16: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.

2 participants