mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
Fix pod lock collision, empty credential validation, and interval parsing
- Override initialize_focus_export_job in VantageLogger to use VANTAGE_USAGE_DATA_JOB_NAME as the Redis pod lock key, preventing silent export skips when both Focus and Vantage loggers are configured - Add field_validator to VantageInitRequest rejecting empty-string api_key and integration_token at init time instead of at export time - Guard FocusLogger FOCUS_INTERVAL_SECONDS with try/except matching the pattern already used in VantageLogger Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4a9d03f1b1
commit
212cd0e4aa
3 changed files with 48 additions and 2 deletions
|
|
@ -53,7 +53,15 @@ class FocusLogger(CustomLogger):
|
|||
if interval_seconds is not None
|
||||
else os.getenv("FOCUS_INTERVAL_SECONDS")
|
||||
)
|
||||
self.interval_seconds = int(raw_interval) if raw_interval is not None else None
|
||||
self.interval_seconds: Optional[int] = None
|
||||
if raw_interval is not None:
|
||||
try:
|
||||
self.interval_seconds = int(raw_interval)
|
||||
except (ValueError, TypeError):
|
||||
verbose_logger.warning(
|
||||
"Invalid FOCUS_INTERVAL_SECONDS value: %s, ignoring",
|
||||
raw_interval,
|
||||
)
|
||||
env_prefix = os.getenv("FOCUS_PREFIX")
|
||||
self.prefix: str = (
|
||||
prefix if prefix is not None else (env_prefix if env_prefix else "focus_exports")
|
||||
|
|
|
|||
|
|
@ -86,6 +86,37 @@ class VantageLogger(FocusLogger):
|
|||
resolved_token[:4] + "***" if resolved_token and len(resolved_token) > 4 else "***",
|
||||
)
|
||||
|
||||
async def initialize_focus_export_job(self) -> None:
|
||||
"""Override to use the Vantage-specific pod lock key.
|
||||
|
||||
Without this, VantageLogger and FocusLogger would compete for the
|
||||
same ``FOCUS_USAGE_DATA_JOB_NAME`` lock, causing one to silently
|
||||
skip its export cycle when both are configured simultaneously.
|
||||
"""
|
||||
from litellm.proxy.proxy_server import proxy_logging_obj
|
||||
|
||||
pod_lock_manager = None
|
||||
if proxy_logging_obj is not None:
|
||||
writer = getattr(proxy_logging_obj, "db_spend_update_writer", None)
|
||||
if writer is not None:
|
||||
pod_lock_manager = getattr(writer, "pod_lock_manager", None)
|
||||
|
||||
if pod_lock_manager and pod_lock_manager.redis_cache:
|
||||
acquired = await pod_lock_manager.acquire_lock(
|
||||
cronjob_id=VANTAGE_USAGE_DATA_JOB_NAME
|
||||
)
|
||||
if not acquired:
|
||||
verbose_logger.debug("Vantage export: unable to acquire pod lock")
|
||||
return
|
||||
try:
|
||||
await self._run_scheduled_export()
|
||||
finally:
|
||||
await pod_lock_manager.release_lock(
|
||||
cronjob_id=VANTAGE_USAGE_DATA_JOB_NAME
|
||||
)
|
||||
else:
|
||||
await self._run_scheduled_export()
|
||||
|
||||
@staticmethod
|
||||
async def init_vantage_background_job(
|
||||
scheduler: AsyncIOScheduler,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Vantage endpoint types for LiteLLM Proxy
|
|||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
class VantageInitRequest(BaseModel):
|
||||
|
|
@ -20,6 +20,13 @@ class VantageInitRequest(BaseModel):
|
|||
description="Vantage API base URL (default: https://api.vantage.sh)",
|
||||
)
|
||||
|
||||
@field_validator("api_key", "integration_token")
|
||||
@classmethod
|
||||
def must_be_non_empty(cls, v: str) -> str:
|
||||
if not v.strip():
|
||||
raise ValueError("must be a non-empty string")
|
||||
return v
|
||||
|
||||
|
||||
class VantageInitResponse(BaseModel):
|
||||
"""Response model for Vantage initialization"""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue