Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@


## Unreleased
### Added
- GitManager.fetch() cooldown to avoid redundant remote fetches, controlled by GIT_FETCH_COOLDOWN env var (default 30s)


## 1.2.0
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Unreleased:
added: []
added:
- "GitManager.fetch() cooldown to avoid redundant remote fetches, controlled by GIT_FETCH_COOLDOWN env var (default 30s)"
fixed: []
changed: []
deprecated: []
Expand Down
32 changes: 30 additions & 2 deletions src/ctl/util/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import os
import shutil
import tempfile
import time
import urllib
import uuid
from typing import Callable, Union
Expand Down Expand Up @@ -148,6 +149,7 @@ def __init__(
self.submodules = submodules

self.services = Services()
self._last_fetch_time = 0

self.log = log if log else logging.getLogger(__name__)

Expand Down Expand Up @@ -394,18 +396,44 @@ def service_file_url(self, file_path: str, service: str = None):

return f"{_service.instance_url}/{_project.full_repo_name}/blob/{self.branch}/{file_path}"

def fetch(self, prune: bool = True):
def fetch(self, prune: bool = True, force: bool = False):
"""
Fetches the origin repository
Fetches the origin repository.

Respects a cooldown period to avoid hammering the remote with
redundant fetches (e.g. multiple fetches within a single
EphemeralGitContext entry). The cooldown is controlled by the
GIT_FETCH_COOLDOWN environment variable (seconds, default 30).

Args:
prune: Whether to prune deleted remote branches
force: If True, bypass the cooldown and always fetch
"""

try:
cooldown = int(os.environ.get("GIT_FETCH_COOLDOWN", 30))
except (ValueError, TypeError):
self.log.error(f"Invalid GIT_FETCH_COOLDOWN value: {os.environ.get('GIT_FETCH_COOLDOWN')!r}, using default 30s")
cooldown = 30

if not force and cooldown > 0:
now = time.time()
elapsed = now - self._last_fetch_time
if elapsed < cooldown:
self.log.debug(
f"Skipping fetch, last fetch was {elapsed:.1f}s ago "
f"(cooldown={cooldown}s)"
)
return

fetch_args = ["--all"]
if prune:
fetch_args.append("--prune")

self.log.info(f"Fetching from {self.origin.name}")
fetch_info = self.repo.git.fetch(*fetch_args)
self.log.debug(f"Fetch info: {fetch_info}")
self._last_fetch_time = time.time()
return fetch_info

def pull(self):
Expand Down
Loading