Files
aitbc/dev/cache/aitbc_cache/config.py
oib f353e00172 chore(security): enhance environment configuration, CI workflows, and wallet daemon with security improvements
- Restructure .env.example with security-focused documentation, service-specific environment file references, and AWS Secrets Manager integration
- Update CLI tests workflow to single Python 3.13 version, add pytest-mock dependency, and consolidate test execution with coverage
- Add comprehensive security validation to package publishing workflow with manual approval gates, secret scanning, and release
2026-03-03 10:33:46 +01:00

344 lines
12 KiB
Python

"""
Cache Configuration for AITBC Event-Driven Caching System
Configuration settings for Redis distributed caching with event-driven invalidation
across global edge nodes for GPU marketplace and real-time data.
"""
import os
from typing import Dict, Any, Optional
from dataclasses import dataclass
@dataclass
class RedisConfig:
"""Redis connection configuration"""
host: str = "localhost"
port: int = 6379
db: int = 0
password: Optional[str] = None
ssl: bool = False
max_connections: int = 20
socket_timeout: int = 5
socket_connect_timeout: int = 5
retry_on_timeout: bool = True
health_check_interval: int = 30
@dataclass
class CacheConfig:
"""Cache behavior configuration"""
l1_cache_size: int = 1000
l1_ttl_multiplier: float = 0.5 # L1 cache TTL as fraction of L2 TTL
event_queue_size: int = 10000
event_processing_timeout: int = 30
invalidation_batch_size: int = 100
stats_retention_hours: int = 24
health_check_interval: int = 60
@dataclass
class EdgeNodeConfig:
"""Edge node configuration"""
node_id: Optional[str] = None
region: str = "default"
datacenter: str = "default"
rack: Optional[str] = None
availability_zone: Optional[str] = None
network_tier: str = "standard" # standard, premium, edge
cache_tier: str = "edge" # edge, regional, global
@dataclass
class EventDrivenCacheSettings:
"""Complete event-driven cache settings"""
redis: RedisConfig
cache: CacheConfig
edge_node: EdgeNodeConfig
# Feature flags
enable_l1_cache: bool = True
enable_event_driven_invalidation: bool = True
enable_compression: bool = True
enable_metrics: bool = True
enable_health_checks: bool = True
# Performance settings
connection_pool_size: int = 20
max_event_queue_size: int = 10000
event_processing_workers: int = 4
cache_warmup_enabled: bool = True
# Security settings
enable_tls: bool = False
require_auth: bool = False
auth_token: Optional[str] = None
def load_config_from_env() -> EventDrivenCacheSettings:
"""Load configuration from environment variables"""
# Redis configuration
redis_config = RedisConfig(
host=os.getenv("REDIS_HOST", "localhost"),
port=int(os.getenv("REDIS_PORT", "6379")),
db=int(os.getenv("REDIS_DB", "0")),
password=os.getenv("REDIS_PASSWORD"),
ssl=os.getenv("REDIS_SSL", "false").lower() == "true",
max_connections=int(os.getenv("REDIS_MAX_CONNECTIONS", "20")),
socket_timeout=int(os.getenv("REDIS_SOCKET_TIMEOUT", "5")),
socket_connect_timeout=int(os.getenv("REDIS_SOCKET_CONNECT_TIMEOUT", "5")),
retry_on_timeout=os.getenv("REDIS_RETRY_ON_TIMEOUT", "true").lower() == "true",
health_check_interval=int(os.getenv("REDIS_HEALTH_CHECK_INTERVAL", "30"))
)
# Cache configuration
cache_config = CacheConfig(
l1_cache_size=int(os.getenv("CACHE_L1_SIZE", "1000")),
l1_ttl_multiplier=float(os.getenv("CACHE_L1_TTL_MULTIPLIER", "0.5")),
event_queue_size=int(os.getenv("CACHE_EVENT_QUEUE_SIZE", "10000")),
event_processing_timeout=int(os.getenv("CACHE_EVENT_PROCESSING_TIMEOUT", "30")),
invalidation_batch_size=int(os.getenv("CACHE_INVALIDATION_BATCH_SIZE", "100")),
stats_retention_hours=int(os.getenv("CACHE_STATS_RETENTION_HOURS", "24")),
health_check_interval=int(os.getenv("CACHE_HEALTH_CHECK_INTERVAL", "60"))
)
# Edge node configuration
edge_node_config = EdgeNodeConfig(
node_id=os.getenv("EDGE_NODE_ID"),
region=os.getenv("EDGE_NODE_REGION", "default"),
datacenter=os.getenv("EDGE_NODE_DATACENTER", "default"),
rack=os.getenv("EDGE_NODE_RACK"),
availability_zone=os.getenv("EDGE_NODE_AVAILABILITY_ZONE"),
network_tier=os.getenv("EDGE_NODE_NETWORK_TIER", "standard"),
cache_tier=os.getenv("EDGE_NODE_CACHE_TIER", "edge")
)
# Feature flags
enable_l1_cache = os.getenv("CACHE_ENABLE_L1", "true").lower() == "true"
enable_event_driven_invalidation = os.getenv("CACHE_ENABLE_EVENT_DRIVEN", "true").lower() == "true"
enable_compression = os.getenv("CACHE_ENABLE_COMPRESSION", "true").lower() == "true"
enable_metrics = os.getenv("CACHE_ENABLE_METRICS", "true").lower() == "true"
enable_health_checks = os.getenv("CACHE_ENABLE_HEALTH_CHECKS", "true").lower() == "true"
# Performance settings
connection_pool_size = int(os.getenv("CACHE_CONNECTION_POOL_SIZE", "20"))
max_event_queue_size = int(os.getenv("CACHE_MAX_EVENT_QUEUE_SIZE", "10000"))
event_processing_workers = int(os.getenv("CACHE_EVENT_PROCESSING_WORKERS", "4"))
cache_warmup_enabled = os.getenv("CACHE_WARMUP_ENABLED", "true").lower() == "true"
# Security settings
enable_tls = os.getenv("CACHE_ENABLE_TLS", "false").lower() == "true"
require_auth = os.getenv("CACHE_REQUIRE_AUTH", "false").lower() == "true"
auth_token = os.getenv("CACHE_AUTH_TOKEN")
return EventDrivenCacheSettings(
redis=redis_config,
cache=cache_config,
edge_node=edge_node_config,
enable_l1_cache=enable_l1_cache,
enable_event_driven_invalidation=enable_event_driven_invalidation,
enable_compression=enable_compression,
enable_metrics=enable_metrics,
enable_health_checks=enable_health_checks,
connection_pool_size=connection_pool_size,
max_event_queue_size=max_event_queue_size,
event_processing_workers=event_processing_workers,
cache_warmup_enabled=cache_warmup_enabled,
enable_tls=enable_tls,
require_auth=require_auth,
auth_token=auth_token
)
def get_redis_url(config: RedisConfig) -> str:
"""Construct Redis URL from configuration"""
auth_part = ""
if config.password:
auth_part = f":{config.password}@"
ssl_part = "s" if config.ssl else ""
return f"redis{ssl_part}://{auth_part}{config.host}:{config.port}/{config.db}"
# Default configurations for different environments
def get_development_config() -> EventDrivenCacheSettings:
"""Development environment configuration"""
return EventDrivenCacheSettings(
redis=RedisConfig(
host="localhost",
port=6379,
db=1, # Use different DB for development
ssl=False
),
cache=CacheConfig(
l1_cache_size=100, # Smaller cache for development
l1_ttl_multiplier=0.3,
event_queue_size=1000
),
edge_node=EdgeNodeConfig(
node_id="dev_node",
region="development"
),
enable_metrics=False, # Disable overhead in development
enable_health_checks=False
)
def get_staging_config() -> EventDrivenCacheSettings:
"""Staging environment configuration"""
return EventDrivenCacheSettings(
redis=RedisConfig(
host="redis-staging.internal",
port=6379,
db=0,
ssl=True
),
cache=CacheConfig(
l1_cache_size=500,
l1_ttl_multiplier=0.4,
event_queue_size=5000
),
edge_node=EdgeNodeConfig(
node_id=None, # Auto-generate
region="staging"
),
enable_metrics=True,
enable_health_checks=True
)
def get_production_config() -> EventDrivenCacheSettings:
"""Production environment configuration"""
return EventDrivenCacheSettings(
redis=RedisConfig(
host=os.getenv("REDIS_CLUSTER_HOST", "redis-cluster.internal"),
port=int(os.getenv("REDIS_CLUSTER_PORT", "6379")),
db=0,
password=os.getenv("REDIS_CLUSTER_PASSWORD"),
ssl=True,
max_connections=50,
socket_timeout=10,
socket_connect_timeout=10,
health_check_interval=15
),
cache=CacheConfig(
l1_cache_size=2000,
l1_ttl_multiplier=0.6,
event_queue_size=20000,
event_processing_timeout=60,
invalidation_batch_size=200,
health_check_interval=30
),
edge_node=EdgeNodeConfig(
node_id=None, # Auto-generate from hostname/IP
region=os.getenv("EDGE_NODE_REGION", "global"),
datacenter=os.getenv("EDGE_NODE_DATACENTER"),
availability_zone=os.getenv("EDGE_NODE_AZ"),
network_tier="premium",
cache_tier="edge"
),
enable_l1_cache=True,
enable_event_driven_invalidation=True,
enable_compression=True,
enable_metrics=True,
enable_health_checks=True,
connection_pool_size=50,
max_event_queue_size=20000,
event_processing_workers=8,
cache_warmup_enabled=True,
enable_tls=True,
require_auth=True,
auth_token=os.getenv("CACHE_AUTH_TOKEN")
)
def get_edge_node_config(region: str) -> EventDrivenCacheSettings:
"""Configuration for edge nodes in specific regions"""
base_config = get_production_config()
# Override edge node specific settings
base_config.edge_node.region = region
base_config.edge_node.cache_tier = "edge"
base_config.edge_node.network_tier = "edge"
# Edge nodes have smaller L1 cache but faster event processing
base_config.cache.l1_cache_size = 500
base_config.cache.l1_ttl_multiplier = 0.3
base_config.event_processing_workers = 2
return base_config
def get_regional_cache_config(region: str) -> EventDrivenCacheSettings:
"""Configuration for regional cache nodes"""
base_config = get_production_config()
# Override regional cache settings
base_config.edge_node.region = region
base_config.edge_node.cache_tier = "regional"
base_config.edge_node.network_tier = "premium"
# Regional caches have larger L1 cache
base_config.cache.l1_cache_size = 5000
base_config.cache.l1_ttl_multiplier = 0.8
base_config.event_processing_workers = 6
return base_config
# Configuration validation
def validate_config(config: EventDrivenCacheSettings) -> bool:
"""Validate cache configuration"""
errors = []
# Redis configuration validation
if not config.redis.host:
errors.append("Redis host is required")
if not (1 <= config.redis.port <= 65535):
errors.append("Redis port must be between 1 and 65535")
if not (0 <= config.redis.db <= 15):
errors.append("Redis DB must be between 0 and 15")
# Cache configuration validation
if config.cache.l1_cache_size <= 0:
errors.append("L1 cache size must be positive")
if not (0.1 <= config.cache.l1_ttl_multiplier <= 1.0):
errors.append("L1 TTL multiplier must be between 0.1 and 1.0")
if config.cache.event_queue_size <= 0:
errors.append("Event queue size must be positive")
# Edge node configuration validation
if not config.edge_node.region:
errors.append("Edge node region is required")
if config.edge_node.cache_tier not in ["edge", "regional", "global"]:
errors.append("Cache tier must be one of: edge, regional, global")
if errors:
raise ValueError(f"Configuration validation failed: {', '.join(errors)}")
return True
# Environment-specific configuration loader
def get_config_for_environment(env: str = None) -> EventDrivenCacheSettings:
"""Get configuration for specific environment"""
env = env or os.getenv("ENVIRONMENT", "development").lower()
if env == "production":
return get_production_config()
elif env == "staging":
return get_staging_config()
elif env == "development":
return get_development_config()
else:
# Default to environment variables
return load_config_from_env()