diff --git a/ivatar/views.py b/ivatar/views.py index 09ba6b2..323fdcf 100644 --- a/ivatar/views.py +++ b/ivatar/views.py @@ -845,9 +845,11 @@ class StatsView(TemplateView, JsonResponse): return JsonResponse(retval) -# Thread-safe version cache +# Thread-safe version cache with timestamp _version_cache = None +_version_cache_timestamp = None _version_cache_lock = threading.Lock() +_VERSION_CACHE_TTL = 300 # 5 minutes cache TTL def _get_git_info_from_files(): @@ -889,15 +891,29 @@ def _get_git_info_from_files(): branch_name = "detached" # Try to get commit date from git log file (if available) + # Optimize: read only the last line instead of entire file commit_date = None log_file = path.join(git_dir, "logs", "HEAD") if path.exists(log_file): try: - with open(log_file, "r") as f: - # Read last line to get most recent commit info - lines = f.readlines() - if lines: - last_line = lines[-1].strip() + with open(log_file, "rb") as f: + # Seek to end and read backwards to find last line + f.seek(0, 2) # Seek to end + file_size = f.tell() + + # Read backwards in chunks to find the last line + chunk_size = min(1024, file_size) + f.seek(max(0, file_size - chunk_size)) + chunk = f.read().decode("utf-8", errors="ignore") + + # Find the last newline + last_newline = chunk.rfind("\n") + if last_newline != -1: + last_line = chunk[last_newline + 1:].strip() + else: + last_line = chunk.strip() + + if last_line: # Git log format: parts = last_line.split("\t") if len(parts) >= 2: @@ -910,7 +926,7 @@ def _get_git_info_from_files(): commit_date = datetime.datetime.fromtimestamp( timestamp ).strftime("%Y-%m-%d %H:%M:%S %z") - except (ValueError, IndexError): + except (ValueError, IndexError, UnicodeDecodeError): pass # Fallback: try to get date from commit object if available @@ -941,21 +957,33 @@ def _get_git_info_from_files(): def _get_cached_version_info(): """ - Get cached version information, loading it if not available + Get cached version information, loading it if not available or expired """ - global _version_cache + global _version_cache, _version_cache_timestamp + import time with _version_cache_lock: - if _version_cache is None: + current_time = time.time() + + # Check if cache is expired or doesn't exist + if ( + _version_cache is None + or _version_cache_timestamp is None + or current_time - _version_cache_timestamp > _VERSION_CACHE_TTL + ): + # Get version info from git files _version_cache = _get_git_info_from_files() + _version_cache_timestamp = current_time - # If that fails, return error + # If that fails, return error but don't cache it for long if _version_cache is None: _version_cache = { "error": "Unable to determine version - .git directory not found", "deployment_status": "unknown", } + # Set shorter TTL for error cases to allow retry + _version_cache_timestamp = current_time - _VERSION_CACHE_TTL + 30 return _version_cache