From e5ac267935a4a41db92672f5fb4b2418d20f3cc7 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 18 Jun 2025 12:30:42 -0700 Subject: [PATCH] ttl deletion for rate limits --- src/backend/agents/generate_image.py | 2 +- src/backend/agents/generate_persona.py | 1 - src/backend/agents/job_requirements.py | 1 - src/backend/agents/skill_match.py | 1 - src/backend/background_tasks.py | 14 ++++--- src/backend/main.py | 2 +- src/backend/model_cast.py | 53 -------------------------- src/backend/utils/dependencies.py | 3 +- 8 files changed, 11 insertions(+), 66 deletions(-) delete mode 100644 src/backend/model_cast.py diff --git a/src/backend/agents/generate_image.py b/src/backend/agents/generate_image.py index 2d6b0f5..b68eafa 100644 --- a/src/backend/agents/generate_image.py +++ b/src/backend/agents/generate_image.py @@ -25,7 +25,7 @@ import hashlib from .base import Agent, agent_registry, LLMMessage from models import ActivityType, ApiActivityType, Candidate, ChatMessage, ChatMessageError, ChatMessageMetaData, ApiMessageType, ChatMessageStatus, ChatMessageStreaming, ChatMessageUser, ChatOptions, ChatSenderType, ApiStatusType, Tunables -import model_cast +import helpers.model_cast as model_cast from logger import logger import defines import backstory_traceback as traceback diff --git a/src/backend/agents/generate_persona.py b/src/backend/agents/generate_persona.py index 5d895e4..7d5f1d1 100644 --- a/src/backend/agents/generate_persona.py +++ b/src/backend/agents/generate_persona.py @@ -27,7 +27,6 @@ from names_dataset import NameDataset, NameWrapper # type: ignore from .base import Agent, agent_registry, LLMMessage from models import ApiActivityType, Candidate, ChatMessage, ChatMessageError, ChatMessageMetaData, ApiMessageType, ChatMessageStatus, ChatMessageStreaming, ChatMessageUser, ChatOptions, ChatSenderType, ApiStatusType, Tunables -import model_cast from logger import logger import defines import backstory_traceback as traceback diff --git a/src/backend/agents/job_requirements.py b/src/backend/agents/job_requirements.py index 785805b..9f02325 100644 --- a/src/backend/agents/job_requirements.py +++ b/src/backend/agents/job_requirements.py @@ -20,7 +20,6 @@ import numpy as np # type: ignore from .base import Agent, agent_registry, LLMMessage from models import ApiActivityType, ApiMessage, Candidate, ChatMessage, ChatMessageError, ChatMessageMetaData, ApiMessageType, ChatMessageStatus, ChatMessageStreaming, ChatMessageUser, ChatOptions, ChatSenderType, ApiStatusType, Job, JobRequirements, JobRequirementsMessage, Tunables -import model_cast from logger import logger import defines import backstory_traceback as traceback diff --git a/src/backend/agents/skill_match.py b/src/backend/agents/skill_match.py index 4d0c6cd..e03030f 100644 --- a/src/backend/agents/skill_match.py +++ b/src/backend/agents/skill_match.py @@ -22,7 +22,6 @@ from .base import Agent, agent_registry, LLMMessage from models import (ApiMessage, Candidate, ChatMessage, ChatMessageError, ChatMessageMetaData, ApiMessageType, ChatMessageRagSearch, ChatMessageSkillAssessment, ChatMessageStatus, ChatMessageStreaming, ChatMessageUser, ChatOptions, ChatSenderType, ApiStatusType, EvidenceDetail, SkillAssessment, Tunables) -import model_cast from logger import logger import defines import backstory_traceback as traceback diff --git a/src/backend/background_tasks.py b/src/backend/background_tasks.py index 5f7f2aa..c2e298e 100644 --- a/src/backend/background_tasks.py +++ b/src/backend/background_tasks.py @@ -82,10 +82,8 @@ class BackgroundTaskManager: logger.info("Skipping rate limit cleanup - application shutting down") return 0 - database = self.database_manager.get_database() - # Get Redis client safely (using the event loop safe method) - from backend.database.manager import redis_manager + from database.manager import redis_manager redis = await redis_manager.get_client() # Clean up rate limit keys older than specified days @@ -103,9 +101,13 @@ class BackgroundTaskManager: try: ttl = await redis.ttl(key) if ttl == -1: # No expiration set, check creation time - # For simplicity, delete keys without TTL - await redis.delete(key) - deleted_count += 1 + creation_time = await redis.hget(key, "created_at") # type: ignore + if creation_time: + creation_time = datetime.fromisoformat(creation_time).replace(tzinfo=UTC) + if creation_time < cutoff_time: + # Key is older than cutoff, delete it + await redis.delete(key) + deleted_count += 1 except Exception: continue diff --git a/src/backend/main.py b/src/backend/main.py index b1b1deb..015b1e6 100644 --- a/src/backend/main.py +++ b/src/backend/main.py @@ -60,7 +60,7 @@ from auth_utils import ( sanitize_login_input, SecurityConfig ) -import model_cast +import helpers.model_cast as model_cast import defines from logger import logger from database.manager import RedisDatabase, redis_manager, DatabaseManager diff --git a/src/backend/model_cast.py b/src/backend/model_cast.py deleted file mode 100644 index 9a31226..0000000 --- a/src/backend/model_cast.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import Type, TypeVar -from pydantic import BaseModel -import copy - -from models import Candidate, CandidateAI, Employer, Guest, BaseUserWithType - -# Ensure all user models inherit from BaseUserWithType -assert issubclass(Candidate, BaseUserWithType), "Candidate must inherit from BaseUserWithType" -assert issubclass(CandidateAI, BaseUserWithType), "CandidateAI must inherit from BaseUserWithType" -assert issubclass(Employer, BaseUserWithType), "Employer must inherit from BaseUserWithType" -assert issubclass(Guest, BaseUserWithType), "Guest must inherit from BaseUserWithType" - -T = TypeVar('T', bound=BaseModel) - -def cast_to_model(model_cls: Type[T], source: BaseModel) -> T: - data = {field: getattr(source, field) for field in model_cls.__fields__} - return model_cls(**data) - -def cast_to_model_safe(model_cls: Type[T], source: BaseModel) -> T: - data = {field: copy.deepcopy(getattr(source, field)) for field in model_cls.__fields__} - return model_cls(**data) - -def cast_to_base_user_with_type(user) -> BaseUserWithType: - """ - Casts a Candidate, CandidateAI, Employer, or Guest to BaseUserWithType. - This is useful for FastAPI dependencies that expect a common user type. - """ - if isinstance(user, BaseUserWithType): - return user - # If it's a dict, try to detect type - if isinstance(user, dict): - user_type = user.get("user_type") or user.get("type") - if user_type == "candidate": - if user.get("is_AI"): - return CandidateAI.model_validate(user) - return Candidate.model_validate(user) - elif user_type == "employer": - return Employer.model_validate(user) - elif user_type == "guest": - return Guest.model_validate(user) - else: - raise ValueError(f"Unknown user_type: {user_type}") - # If it's a model, check its type - if hasattr(user, "user_type"): - if getattr(user, "user_type", None) == "candidate": - if getattr(user, "is_AI", False): - return CandidateAI.model_validate(user.model_dump()) - return Candidate.model_validate(user.model_dump()) - elif getattr(user, "user_type", None) == "employer": - return Employer.model_validate(user.model_dump()) - elif getattr(user, "user_type", None) == "guest": - return Guest.model_validate(user.model_dump()) - raise TypeError(f"Cannot cast object of type {type(user)} to BaseUserWithType") diff --git a/src/backend/utils/dependencies.py b/src/backend/utils/dependencies.py index 0742308..4941f8a 100644 --- a/src/backend/utils/dependencies.py +++ b/src/backend/utils/dependencies.py @@ -134,11 +134,10 @@ async def get_current_user( # Check candidates candidate_data = await database.get_candidate(user_id) if candidate_data: + from helpers.model_cast import cast_to_base_user_with_type if candidate_data.get("is_AI"): - from model_cast import cast_to_base_user_with_type return cast_to_base_user_with_type(CandidateAI.model_validate(candidate_data)) else: - from model_cast import cast_to_base_user_with_type return cast_to_base_user_with_type(Candidate.model_validate(candidate_data)) # Check employers