ALwrity version 0.5.6
This commit is contained in:
102
backend/models/api_monitoring.py
Normal file
102
backend/models/api_monitoring.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
API Monitoring Database Models
|
||||
Persistent storage for API monitoring statistics.
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Float, Boolean, JSON, Index, Text
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from datetime import datetime
|
||||
import json
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class APIRequest(Base):
|
||||
"""Store individual API requests for monitoring."""
|
||||
|
||||
__tablename__ = "api_requests"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
path = Column(String(500), nullable=False)
|
||||
method = Column(String(10), nullable=False)
|
||||
status_code = Column(Integer, nullable=False)
|
||||
duration = Column(Float, nullable=False) # Response time in seconds
|
||||
user_id = Column(String(50), nullable=True)
|
||||
cache_hit = Column(Boolean, nullable=True)
|
||||
request_size = Column(Integer, nullable=True)
|
||||
response_size = Column(Integer, nullable=True)
|
||||
user_agent = Column(String(500), nullable=True)
|
||||
ip_address = Column(String(45), nullable=True)
|
||||
|
||||
# Indexes for fast queries
|
||||
__table_args__ = (
|
||||
Index('idx_timestamp', 'timestamp'),
|
||||
Index('idx_path_method', 'path', 'method'),
|
||||
Index('idx_status_code', 'status_code'),
|
||||
Index('idx_user_id', 'user_id'),
|
||||
)
|
||||
|
||||
class APIEndpointStats(Base):
|
||||
"""Aggregated statistics per endpoint."""
|
||||
|
||||
__tablename__ = "api_endpoint_stats"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
endpoint = Column(String(500), nullable=False, unique=True) # "GET /api/endpoint"
|
||||
total_requests = Column(Integer, default=0)
|
||||
total_errors = Column(Integer, default=0)
|
||||
total_duration = Column(Float, default=0.0)
|
||||
avg_duration = Column(Float, default=0.0)
|
||||
min_duration = Column(Float, nullable=True)
|
||||
max_duration = Column(Float, nullable=True)
|
||||
last_called = Column(DateTime, nullable=True)
|
||||
cache_hits = Column(Integer, default=0)
|
||||
cache_misses = Column(Integer, default=0)
|
||||
cache_hit_rate = Column(Float, default=0.0)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_endpoint', 'endpoint'),
|
||||
Index('idx_total_requests', 'total_requests'),
|
||||
Index('idx_avg_duration', 'avg_duration'),
|
||||
)
|
||||
|
||||
class SystemHealth(Base):
|
||||
"""System health snapshots."""
|
||||
|
||||
__tablename__ = "system_health"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
status = Column(String(20), nullable=False) # healthy, warning, critical
|
||||
total_requests = Column(Integer, default=0)
|
||||
total_errors = Column(Integer, default=0)
|
||||
error_rate = Column(Float, default=0.0)
|
||||
avg_response_time = Column(Float, default=0.0)
|
||||
cache_hit_rate = Column(Float, default=0.0)
|
||||
active_endpoints = Column(Integer, default=0)
|
||||
metrics = Column(JSON, nullable=True) # Additional metrics
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_timestamp', 'timestamp'),
|
||||
Index('idx_status', 'status'),
|
||||
)
|
||||
|
||||
class CachePerformance(Base):
|
||||
"""Cache performance metrics."""
|
||||
|
||||
__tablename__ = "cache_performance"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
cache_type = Column(String(50), nullable=False) # "comprehensive_user_data", "redis", etc.
|
||||
hits = Column(Integer, default=0)
|
||||
misses = Column(Integer, default=0)
|
||||
hit_rate = Column(Float, default=0.0)
|
||||
avg_response_time = Column(Float, default=0.0)
|
||||
total_requests = Column(Integer, default=0)
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_timestamp', 'timestamp'),
|
||||
Index('idx_cache_type', 'cache_type'),
|
||||
)
|
||||
72
backend/models/comprehensive_user_data_cache.py
Normal file
72
backend/models/comprehensive_user_data_cache.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
Comprehensive User Data Cache Model
|
||||
Caches expensive comprehensive user data operations to improve performance.
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, Integer, String, DateTime, JSON, Index, ForeignKey
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import relationship
|
||||
from datetime import datetime, timedelta
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class ComprehensiveUserDataCache(Base):
|
||||
"""Cache for comprehensive user data to avoid redundant expensive operations."""
|
||||
|
||||
__tablename__ = "comprehensive_user_data_cache"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, nullable=False)
|
||||
strategy_id = Column(Integer, nullable=True)
|
||||
data_hash = Column(String(64), nullable=False) # For cache invalidation
|
||||
comprehensive_data = Column(JSON, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
expires_at = Column(DateTime, nullable=False)
|
||||
last_accessed = Column(DateTime, default=datetime.utcnow)
|
||||
access_count = Column(Integer, default=0)
|
||||
|
||||
# Indexes for fast lookups
|
||||
__table_args__ = (
|
||||
Index('idx_user_strategy', 'user_id', 'strategy_id'),
|
||||
Index('idx_expires_at', 'expires_at'),
|
||||
Index('idx_data_hash', 'data_hash'),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ComprehensiveUserDataCache(user_id={self.user_id}, strategy_id={self.strategy_id}, expires_at={self.expires_at})>"
|
||||
|
||||
@staticmethod
|
||||
def generate_data_hash(user_id: int, strategy_id: int = None, **kwargs) -> str:
|
||||
"""Generate a hash for cache invalidation based on input parameters."""
|
||||
data_string = f"{user_id}_{strategy_id}_{json.dumps(kwargs, sort_keys=True)}"
|
||||
return hashlib.sha256(data_string.encode()).hexdigest()
|
||||
|
||||
@staticmethod
|
||||
def get_default_expiry() -> datetime:
|
||||
"""Get default expiry time (1 hour from now)."""
|
||||
return datetime.utcnow() + timedelta(hours=1)
|
||||
|
||||
def is_expired(self) -> bool:
|
||||
"""Check if the cache entry has expired."""
|
||||
return datetime.utcnow() > self.expires_at
|
||||
|
||||
def touch(self):
|
||||
"""Update last accessed time and increment access count."""
|
||||
self.last_accessed = datetime.utcnow()
|
||||
self.access_count += 1
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert cache entry to dictionary."""
|
||||
return {
|
||||
"id": self.id,
|
||||
"user_id": self.user_id,
|
||||
"strategy_id": self.strategy_id,
|
||||
"data_hash": self.data_hash,
|
||||
"comprehensive_data": self.comprehensive_data,
|
||||
"created_at": self.created_at.isoformat(),
|
||||
"expires_at": self.expires_at.isoformat(),
|
||||
"last_accessed": self.last_accessed.isoformat(),
|
||||
"access_count": self.access_count
|
||||
}
|
||||
Reference in New Issue
Block a user