mirror of
https://git.oceanpay.cc/danial/kami_apple_exchage.git
synced 2025-12-18 22:29:09 +00:00
- Create README.md for deployment instructions including environment requirements and setup steps. - Implement deploy.sh script for automated deployment of development and production environments. - Add combined Docker Compose configuration for frontend and backend services. - Include Redis configuration file for optimized memory management and persistence. - Update frontend Dockerfile to handle Next.js asset paths and static files. - Remove obsolete deployment files and configurations from frontend directory.
261 lines
9.5 KiB
Python
261 lines
9.5 KiB
Python
"""
|
|
应用配置管理
|
|
支持多环境配置和动态配置更新
|
|
"""
|
|
|
|
from typing import Any, Callable
|
|
from pydantic import Field, field_validator
|
|
from pydantic_settings import BaseSettings
|
|
from enum import Enum
|
|
|
|
|
|
class Environment(str, Enum):
|
|
"""环境类型枚举"""
|
|
|
|
LOCAL = "local"
|
|
DEVELOPMENT = "development"
|
|
PRODUCTION = "production"
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""应用配置类"""
|
|
|
|
# 基础配置
|
|
APP_NAME: str = Field(default="Apple Gift Card Exchange", description="应用名称")
|
|
APP_VERSION: str = Field(default="2.0.0", description="应用版本")
|
|
ENVIRONMENT: Environment = Field(default=Environment.LOCAL, description="运行环境")
|
|
DEBUG: bool = Field(default=False, description="调试模式")
|
|
|
|
# 服务配置
|
|
HOST: str = Field(default="0.0.0.0", description="服务监听地址")
|
|
PORT: int = Field(default=8000, description="服务端口")
|
|
WORKERS: int = Field(default=1, description="工作进程数")
|
|
|
|
# 数据库配置
|
|
DATABASE_URL: str = Field(
|
|
default="sqlite:///./data/kami_data.db", description="数据库连接URL"
|
|
)
|
|
DATABASE_POOL_SIZE: int = Field(default=10, description="数据库连接池大小")
|
|
DATABASE_MAX_OVERFLOW: int = Field(default=20, description="数据库连接池最大溢出")
|
|
DATABASE_TIMEOUT: int = Field(default=30, description="数据库连接超时时间")
|
|
|
|
# Redis配置
|
|
REDIS_URL: str = Field(
|
|
default="redis://localhost:6379/0", description="Redis连接URL"
|
|
)
|
|
REDIS_PASSWORD: str | None = Field(default=None, description="Redis密码")
|
|
REDIS_DB: int = Field(default=0, description="Redis数据库编号")
|
|
|
|
# 线程池配置
|
|
MAX_THREADS: int = Field(default=3, description="最大并发线程数")
|
|
THREAD_TIMEOUT: int = Field(default=300, description="线程超时时间(秒)")
|
|
|
|
# 超时配置
|
|
REQUEST_TIMEOUT: int = Field(default=30, description="请求超时时间(秒)")
|
|
PLAYWRIGHT_TIMEOUT: int = Field(
|
|
default=60, description="Playwright操作超时时间(秒)"
|
|
)
|
|
NAVIGATION_TIMEOUT: int = Field(default=30, description="页面导航超时时间(秒)")
|
|
|
|
# 安全配置
|
|
SECRET_KEY: str = Field(default="your-secret-key-here", description="应用密钥")
|
|
# TODO: Fix environment variable parsing for ALLOWED_HOSTS and CORS_ORIGINS
|
|
ALLOWED_HOSTS: list[str] = Field(default=["*"], description="允许的主机列表")
|
|
CORS_ORIGINS: list[str] = Field(default=["*"], description="CORS允许的源列表")
|
|
CORS_METHODS: list[str] = Field(
|
|
default=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
description="CORS允许的方法",
|
|
)
|
|
CORS_HEADERS: list[str] = Field(default=["*"], description="CORS允许的头部")
|
|
|
|
# 日志配置
|
|
LOG_LEVEL: str = Field(default="INFO", description="日志级别")
|
|
LOG_FORMAT: str = Field(default="json", description="日志格式")
|
|
LOG_DIR: str = Field(default="./logs", description="日志目录")
|
|
LOG_FILE: str = Field(default="./logs/app.log", description="日志文件路径")
|
|
LOG_MAX_SIZE: int = Field(default=104857600, description="日志文件最大大小(字节)")
|
|
LOG_BACKUP_COUNT: int = Field(default=10, description="日志文件备份数量")
|
|
|
|
# ==== OpenTelemetry 统一配置 ====
|
|
# 服务基础信息
|
|
OTEL_ENABLED: bool = Field(default=True, description="是否启用OpenTelemetry")
|
|
OTEL_SERVICE_NAME: str = Field(
|
|
default="apple-exchange-backend", description="服务名称"
|
|
)
|
|
OTEL_SERVICE_VERSION: str = Field(default="2.0.0", description="服务版本")
|
|
OTEL_SERVICE_NAMESPACE: str = Field(
|
|
default="apple-exchange", description="服务命名空间"
|
|
)
|
|
|
|
# 统一OTLP导出器配置
|
|
OTEL_EXPORTER_OTLP_ENDPOINT: str = Field(
|
|
default="http://localhost:4317", description="OTLP导出器统一端点"
|
|
)
|
|
OTEL_EXPORTER_OTLP_PROTOCOL: str = Field(
|
|
default="grpc", description="OTLP协议 (grpc, http/protobuf)"
|
|
)
|
|
OTEL_EXPORTER_OTLP_HEADERS: dict[str, str] = Field(
|
|
default_factory=dict, description="OTLP导出器头部信息"
|
|
)
|
|
OTEL_EXPORTER_OTLP_TIMEOUT: int = Field(
|
|
default=30, description="OTLP导出器超时时间(秒)"
|
|
)
|
|
|
|
# 功能模块开关
|
|
OTEL_TRACES_ENABLED: bool = Field(default=True, description="是否启用Trace")
|
|
OTEL_METRICS_ENABLED: bool = Field(default=True, description="是否启用Metrics")
|
|
OTEL_LOGS_ENABLED: bool = Field(default=True, description="是否启用日志导出")
|
|
|
|
# Trace配置
|
|
OTEL_TRACES_SAMPLER: str = Field(
|
|
default="always_on", description="采样器 (always_on, always_off, ratio)"
|
|
)
|
|
OTEL_TRACES_SAMPLER_RATIO: float = Field(
|
|
default=1.0, description="ratio采样器的采样率"
|
|
)
|
|
|
|
# Metrics配置
|
|
OTEL_METRICS_EXPORT_INTERVAL: int = Field(
|
|
default=5000, description="Metrics导出间隔(毫秒)"
|
|
)
|
|
|
|
# gRPC导出器优化配置
|
|
OTEL_GRPC_RETRY_ENABLED: bool = Field(default=True, description="是否启用gRPC重试")
|
|
OTEL_GRPC_RETRY_MAX_ATTEMPTS: int = Field(default=3, description="最大重试次数")
|
|
OTEL_GRPC_RETRY_INITIAL_BACKOFF: float = Field(
|
|
default=1.0, description="初始退避时间(秒)"
|
|
)
|
|
OTEL_GRPC_RETRY_MAX_BACKOFF: float = Field(
|
|
default=60.0, description="最大退避时间(秒)"
|
|
)
|
|
OTEL_GRPC_RETRY_BACKOFF_MULTIPLIER: float = Field(
|
|
default=2.0, description="退避时间倍数"
|
|
)
|
|
|
|
# 批处理器统一配置
|
|
OTEL_BATCH_MAX_QUEUE_SIZE: int = Field(default=2048, description="批处理队列大小")
|
|
OTEL_BATCH_MAX_EXPORT_BATCH_SIZE: int = Field(
|
|
default=512, description="单次导出批量大小"
|
|
)
|
|
OTEL_BATCH_EXPORT_TIMEOUT: int = Field(
|
|
default=30000, description="批处理导出超时(毫秒)"
|
|
)
|
|
OTEL_BATCH_SCHEDULE_DELAY: int = Field(
|
|
default=5000, description="批处理调度延迟(毫秒)"
|
|
)
|
|
|
|
# 性能限制配置
|
|
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT: int = Field(
|
|
default=1024, description="属性值长度限制"
|
|
)
|
|
OTEL_ATTRIBUTE_COUNT_LIMIT: int = Field(default=128, description="属性数量限制")
|
|
OTEL_SPAN_EVENT_COUNT_LIMIT: int = Field(
|
|
default=128, description="Span事件数量限制"
|
|
)
|
|
OTEL_SPAN_LINK_COUNT_LIMIT: int = Field(default=128, description="Span链接数量限制")
|
|
|
|
# 文件存储配置
|
|
UPLOAD_DIR: str = Field(default="./data/uploads", description="上传文件目录")
|
|
SNAPSHOT_DIR: str = Field(default="./data/snapshot", description="截图保存目录")
|
|
HTML_DIR: str = Field(default="./data/html", description="HTML文件保存目录")
|
|
FILE_STORAGE_PATH: str = Field(default="./data/storage", description="文件存储路径")
|
|
MAX_FILE_SIZE: int = Field(default=16777216, description="最大文件大小(字节)")
|
|
|
|
# 健康检查配置
|
|
HEALTH_CHECK_INTERVAL: int = Field(default=30, description="健康检查间隔(秒)")
|
|
|
|
@field_validator("ENVIRONMENT", mode="before")
|
|
@classmethod
|
|
def validate_environment(cls, v):
|
|
"""验证环境配置"""
|
|
if isinstance(v, str):
|
|
return Environment(v.lower())
|
|
return v
|
|
|
|
@field_validator("LOG_LEVEL")
|
|
@classmethod
|
|
def validate_log_level(cls, v):
|
|
"""验证日志级别"""
|
|
valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
|
if v.upper() not in valid_levels:
|
|
raise ValueError(f"日志级别必须是以下之一: {valid_levels}")
|
|
return v.upper()
|
|
|
|
@field_validator("LOG_FORMAT")
|
|
@classmethod
|
|
def validate_log_format(cls, v):
|
|
"""验证日志格式"""
|
|
valid_formats = ["json", "text"]
|
|
if v.lower() not in valid_formats:
|
|
raise ValueError(f"日志格式必须是以下之一: {valid_formats}")
|
|
return v.lower()
|
|
|
|
@field_validator("MAX_THREADS")
|
|
@classmethod
|
|
def validate_max_threads(cls, v):
|
|
"""验证最大线程数"""
|
|
if v < 1:
|
|
raise ValueError("最大线程数必须大于0")
|
|
if v > 50:
|
|
raise ValueError("最大线程数不能超过50")
|
|
return v
|
|
|
|
@field_validator("PORT")
|
|
@classmethod
|
|
def validate_port(cls, v):
|
|
"""验证端口号"""
|
|
if not (1 <= v <= 65535):
|
|
raise ValueError("端口号必须在1-65535之间")
|
|
return v
|
|
|
|
@field_validator("OTEL_TRACES_SAMPLER_RATIO")
|
|
@classmethod
|
|
def validate_sampler_ratio(cls, v):
|
|
"""验证采样器参数"""
|
|
if not (0.0 <= v <= 1.0):
|
|
raise ValueError("采样率必须在0.0-1.0之间")
|
|
return v
|
|
|
|
@field_validator("OTEL_GRPC_RETRY_MAX_ATTEMPTS")
|
|
@classmethod
|
|
def validate_retry_attempts(cls, v):
|
|
"""验证重试次数"""
|
|
if v < 0 or v > 10:
|
|
raise ValueError("重试次数必须在0-10之间")
|
|
return v
|
|
|
|
@field_validator("OTEL_BATCH_MAX_QUEUE_SIZE")
|
|
@classmethod
|
|
def validate_queue_size(cls, v):
|
|
"""验证队列大小"""
|
|
if v < 1 or v > 10000:
|
|
raise ValueError("队列大小必须在1-10000之间")
|
|
return v
|
|
|
|
class Config:
|
|
"""Pydantic配置"""
|
|
|
|
env_file = ".env"
|
|
env_file_encoding = "utf-8"
|
|
case_sensitive = True
|
|
extra = "ignore"
|
|
|
|
|
|
# 全局配置实例
|
|
_settings: Settings | None = None
|
|
|
|
|
|
def get_settings() -> Settings:
|
|
"""获取配置实例(单例模式)"""
|
|
global _settings
|
|
if _settings is None:
|
|
_settings = Settings()
|
|
return _settings
|
|
|
|
|
|
def reload_settings() -> Settings:
|
|
"""重新加载配置"""
|
|
global _settings
|
|
_settings = Settings()
|
|
return _settings
|