mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-14 04:04:03 +00:00
Fix performance issues in /deployment/version/ endpoint
- Add proper cache expiration with 5-minute TTL - Optimize git log file reading to avoid loading entire file - Read only last chunk (1024 bytes) instead of all lines - Add shorter TTL (30s) for error cases to allow retry - Improve error handling with UnicodeDecodeError support - Maintain backward compatibility and security (no subprocess calls) This fixes the 30-second response time issue by implementing efficient caching and optimized file I/O operations.
This commit is contained in:
@@ -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: <old_hash> <new_hash> <author> <timestamp> <timezone> <message>
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user