342 lines
13 KiB
Python
342 lines
13 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
系统配置模块
|
||
提供集中的配置管理,支持开发环境、测试环境和生产环境
|
||
"""
|
||
|
||
import os
|
||
from typing import Dict, Any, Optional, List
|
||
from pydantic import Field
|
||
from pydantic_settings import BaseSettings
|
||
|
||
# 定义数据目录路径
|
||
DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data")
|
||
# 确保数据目录存在
|
||
os.makedirs(DATA_DIR, exist_ok=True)
|
||
|
||
# 服务器配置
|
||
default_server_config = {
|
||
'host': '0.0.0.0',
|
||
'port': 8000,
|
||
'workers': 1,
|
||
'reload': True,
|
||
'log_level': 'info'
|
||
}
|
||
|
||
production_server_config = {
|
||
'host': '0.0.0.0',
|
||
'port': 8000,
|
||
'workers': 4,
|
||
'reload': False,
|
||
'log_level': 'warning'
|
||
}
|
||
|
||
test_server_config = {
|
||
'host': '127.0.0.1',
|
||
'port': 8001,
|
||
'workers': 1,
|
||
'reload': False,
|
||
'log_level': 'debug'
|
||
}
|
||
|
||
# 数据库配置
|
||
default_db_config = {
|
||
'dialect': 'mysql',
|
||
'driver': 'pymysql',
|
||
'username': 'root',
|
||
'password': 'root',
|
||
'host': 'localhost',
|
||
'port': 3306,
|
||
'database': 'vwed_task',
|
||
'charset': 'utf8mb4'
|
||
}
|
||
|
||
# Redis配置
|
||
default_redis_config = {
|
||
'host': 'localhost',
|
||
'port': 6379,
|
||
'db': 0,
|
||
'password': None,
|
||
'prefix': 'vwed:',
|
||
'socket_timeout': 5,
|
||
'socket_connect_timeout': 5,
|
||
'decode_responses': True
|
||
}
|
||
|
||
test_redis_config = {
|
||
'host': 'localhost',
|
||
'port': 6379,
|
||
'db': 1,
|
||
'password': None,
|
||
'prefix': 'vwed_test:',
|
||
'decode_responses': True
|
||
}
|
||
|
||
# 库位服务API端点映射
|
||
storage_api_endpoints = {
|
||
"batch_setting_site": "/site/batch-setting",
|
||
"get_idle_crowded_site": "/site/idle-crowded",
|
||
"get_idle_site": "/site/idle",
|
||
"get_locked_sites_by_task_record_id": "/site/locked-by-task",
|
||
"get_site_attr": "/site/attr",
|
||
"query_idle_site": "/site/query",
|
||
"set_site_attr": "/site/attr",
|
||
"set_site_content": "/site/content",
|
||
"set_site_empty": "/site/empty",
|
||
"set_site_filled": "/site/filled",
|
||
"set_site_locked": "/site/lock",
|
||
"set_site_tags": "/site/tags",
|
||
"set_site_unlocked": "/site/unlock"
|
||
}
|
||
|
||
# 库位服务API HTTP方法映射
|
||
storage_api_methods = {
|
||
"batch_setting_site": "POST",
|
||
"get_idle_crowded_site": "GET",
|
||
"get_idle_site": "GET",
|
||
"get_locked_sites_by_task_record_id": "GET",
|
||
"get_site_attr": "GET",
|
||
"query_idle_site": "GET",
|
||
"set_site_attr": "PUT",
|
||
"set_site_content": "PUT",
|
||
"set_site_empty": "PUT",
|
||
"set_site_filled": "PUT",
|
||
"set_site_locked": "PUT",
|
||
"set_site_tags": "PUT",
|
||
"set_site_unlocked": "PUT"
|
||
}
|
||
|
||
# 机器人调度服务API端点映射
|
||
robot_api_endpoints = {
|
||
"vehicle_station": "/robot/station",
|
||
"get_battery_level": "/robot/battery",
|
||
"get_pgv_code": "/robot/pgv-code"
|
||
}
|
||
|
||
# 机器人调度服务API HTTP方法映射
|
||
robot_api_methods = {
|
||
"vehicle_station": "GET",
|
||
"get_battery_level": "GET",
|
||
"get_pgv_code": "GET"
|
||
}
|
||
|
||
# 外部服务API配置
|
||
external_api_config = {
|
||
"storage": {
|
||
"base_url": "http://localhost:8080/api/storage",
|
||
"endpoints": storage_api_endpoints,
|
||
"methods": storage_api_methods
|
||
},
|
||
"robot": {
|
||
"base_url": "http://localhost:8080/api/robot",
|
||
"endpoints": robot_api_endpoints,
|
||
"methods": robot_api_methods
|
||
}
|
||
}
|
||
|
||
def get_config_for_env(env: str, config_type: str) -> Dict[str, Any]:
|
||
"""根据环境获取配置"""
|
||
if config_type == 'server':
|
||
if env == 'production':
|
||
return production_server_config
|
||
elif env == 'test':
|
||
return test_server_config
|
||
return default_server_config
|
||
|
||
elif config_type == 'db':
|
||
# 目前只有默认数据库配置
|
||
return default_db_config
|
||
|
||
elif config_type == 'redis':
|
||
if env == 'test':
|
||
return test_redis_config
|
||
return default_redis_config
|
||
|
||
return {}
|
||
|
||
|
||
class BaseConfig(BaseSettings):
|
||
"""基础配置类"""
|
||
# 应用信息
|
||
APP_NAME: str = "VWED任务系统"
|
||
APP_VERSION: str = "1.0.0"
|
||
APP_DESCRIPTION: str = "自动化移动机器人(AMR)任务管理系统"
|
||
|
||
# 系统设置
|
||
DEBUG: bool = False
|
||
API_PREFIX: str = "/api"
|
||
|
||
# 获取当前环境
|
||
_env: str = os.getenv("APP_ENV", "development").lower()
|
||
|
||
# 服务配置
|
||
_server_config = get_config_for_env(_env, 'server')
|
||
SERVER_HOST: str = Field(default=_server_config['host'], env="HOST")
|
||
SERVER_PORT: int = Field(default=_server_config['port'], env="PORT")
|
||
SERVER_WORKERS: int = Field(default=_server_config['workers'], env="WORKERS")
|
||
SERVER_RELOAD: bool = Field(default=_server_config['reload'], env="RELOAD")
|
||
SERVER_LOG_LEVEL: str = Field(default=_server_config['log_level'], env="LOG_LEVEL")
|
||
|
||
# Modbus设备配置
|
||
MODBUS_MOCK_MODE: bool = Field(default=True, env="MODBUS_MOCK_MODE") # 测试模式:True表示启用模拟数据
|
||
MODBUS_TIMEOUT: float = Field(default=2.0, env="MODBUS_TIMEOUT") # Modbus通信超时时间(秒)
|
||
MODBUS_RETRY_INTERVAL: float = Field(default=1.0, env="MODBUS_RETRY_INTERVAL") # 重试间隔时间(秒)
|
||
MODBUS_POLL_INTERVAL: float = Field(default=0.5, env="MODBUS_POLL_INTERVAL") # 轮询间隔时间(秒)
|
||
|
||
# 数据库连接配置
|
||
_db_config = get_config_for_env(_env, 'db')
|
||
DB_DIALECT: str = Field(default=_db_config['dialect'], env="DB_DIALECT")
|
||
DB_DRIVER: str = Field(default=_db_config['driver'], env="DB_DRIVER")
|
||
DB_USER: str = Field(default=_db_config['username'], env="DB_USER")
|
||
DB_PASSWORD: str = Field(default=_db_config['password'], env="DB_PASSWORD")
|
||
DB_HOST: str = Field(default=_db_config['host'], env="DB_HOST")
|
||
DB_PORT: str = Field(default=str(_db_config['port']), env="DB_PORT")
|
||
DB_NAME: str = Field(default=_db_config['database'], env="DB_NAME")
|
||
DB_CHARSET: str = Field(default=_db_config['charset'], env="DB_CHARSET")
|
||
DB_ECHO: bool = False # 是否输出SQL语句
|
||
DB_POOL_SIZE: int = 10
|
||
DB_MAX_OVERFLOW: int = 20
|
||
DB_POOL_RECYCLE: int = 3600 # 连接池回收时间,防止连接过期
|
||
|
||
# Redis配置
|
||
_redis_config = get_config_for_env(_env, 'redis')
|
||
REDIS_HOST: str = Field(default=_redis_config['host'], env="REDIS_HOST")
|
||
REDIS_PORT: int = Field(default=_redis_config['port'], env="REDIS_PORT")
|
||
REDIS_DB: int = Field(default=_redis_config['db'], env="REDIS_DB")
|
||
REDIS_PASSWORD: Optional[str] = Field(default=_redis_config['password'], env="REDIS_PASSWORD")
|
||
REDIS_PREFIX: str = Field(default=_redis_config['prefix'], env="REDIS_PREFIX")
|
||
REDIS_SOCKET_TIMEOUT: int = Field(default=_redis_config['socket_timeout'], env="REDIS_SOCKET_TIMEOUT")
|
||
REDIS_SOCKET_CONNECT_TIMEOUT: int = Field(default=_redis_config['socket_connect_timeout'], env="REDIS_SOCKET_CONNECT_TIMEOUT")
|
||
REDIS_DECODE_RESPONSES: bool = Field(default=_redis_config['decode_responses'], env="REDIS_DECODE_RESPONSES")
|
||
|
||
# 安全设置
|
||
SECRET_KEY: str = Field(default="YOUR_SECRET_KEY_HERE", env="SECRET_KEY")
|
||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 # 1天
|
||
|
||
# 外部服务API通用配置
|
||
API_TIMEOUT: int = Field(default=30, env="API_TIMEOUT") # 请求超时时间(秒)
|
||
API_TOKEN: Optional[str] = Field(default=None, env="API_TOKEN") # API通用认证令牌
|
||
API_MOCK_MODE: bool = Field(default=False, env="API_MOCK_MODE") # 是否启用API模拟模式
|
||
|
||
# 库位服务API配置
|
||
STORAGE_API_BASE_URL: str = Field(default=external_api_config["storage"]["base_url"], env="STORAGE_API_BASE_URL")
|
||
STORAGE_API_ENDPOINTS: Dict[str, str] = external_api_config["storage"]["endpoints"]
|
||
STORAGE_API_METHODS: Dict[str, str] = external_api_config["storage"]["methods"]
|
||
STORAGE_API_TIMEOUT: int = Field(default=30, env="STORAGE_API_TIMEOUT")
|
||
STORAGE_API_TOKEN: Optional[str] = Field(default=None, env="STORAGE_API_TOKEN")
|
||
STORAGE_API_MOCK_MODE: bool = Field(default=False, env="STORAGE_API_MOCK_MODE")
|
||
|
||
# 机器人调度服务API配置
|
||
ROBOT_API_BASE_URL: str = Field(default=external_api_config["robot"]["base_url"], env="ROBOT_API_BASE_URL")
|
||
ROBOT_API_ENDPOINTS: Dict[str, str] = external_api_config["robot"]["endpoints"]
|
||
ROBOT_API_METHODS: Dict[str, str] = external_api_config["robot"]["methods"]
|
||
ROBOT_API_TIMEOUT: int = Field(default=30, env="ROBOT_API_TIMEOUT")
|
||
ROBOT_API_TOKEN: Optional[str] = Field(default=None, env="ROBOT_API_TOKEN")
|
||
ROBOT_API_MOCK_MODE: bool = Field(default=False, env="ROBOT_API_MOCK_MODE")
|
||
|
||
# CORS设置
|
||
CORS_ORIGINS: List[str] = ["*"]
|
||
CORS_ALLOW_CREDENTIALS: bool = True
|
||
CORS_ALLOW_METHODS: List[str] = ["*"]
|
||
CORS_ALLOW_HEADERS: List[str] = ["*"]
|
||
|
||
# 日志设置
|
||
LOG_LEVEL: str = "INFO"
|
||
LOG_FILE: str = "logs/app.log"
|
||
LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||
|
||
# 任务调度设置
|
||
TASK_SCHEDULER_WORKER_COUNT: int = 5 # 任务调度器工作线程数量
|
||
|
||
# 脚本执行配置
|
||
SCRIPT_TIMEOUT: int = os.getenv("SCRIPT_TIMEOUT", 60) # 脚本执行超时时间(秒)
|
||
SCRIPT_MAX_WORKERS: int = os.getenv("SCRIPT_MAX_WORKERS", 5) # 脚本执行最大线程数
|
||
|
||
# 任务导出加密配置
|
||
TASK_EXPORT_ENCRYPTION_KEY: str = Field(default="vwed_task_export_secret_key", env="TASK_EXPORT_ENCRYPTION_KEY") # 导出加密密钥
|
||
TASK_EXPORT_ENCRYPTION_ALGORITHM: str = Field(default="AES", env="TASK_EXPORT_ENCRYPTION_ALGORITHM") # 加密算法
|
||
TASK_EXPORT_IV: str = Field(default="vwed1234task5678", env="TASK_EXPORT_IV") # 初始化向量
|
||
|
||
# 增强版任务调度器配置
|
||
TASK_SCHEDULER_MIN_WORKER_COUNT: int = 15 # 最小工作线程数
|
||
TASK_SCHEDULER_MAX_WORKER_COUNT: int = 30 # 最大工作线程数
|
||
TASK_SCHEDULER_QUEUE_COUNT: int = 3 # 队列数量
|
||
TASK_SCHEDULER_QUEUE_THRESHOLD_PERCENTILES: List[float] = [0.1, 0.3, 1.0] # 队列阈值百分比配置
|
||
TASK_SCHEDULER_WORKER_RATIOS: List[float] = [0.6, 0.3, 0.1] # 工作线程分配比例
|
||
TASK_SCHEDULER_TASK_TIMEOUT: int = 3600 # 任务超时时间(秒)
|
||
TASK_SCHEDULER_MAX_RETRY_COUNT: int = 3 # 最大重试次数
|
||
TASK_SCHEDULER_RETRY_DELAY: int = 60 # 重试基础延迟(秒)
|
||
TASK_SCHEDULER_BACKUP_INTERVAL: int = 300 # 备份间隔(秒)
|
||
TASK_SCHEDULER_BACKUP_DIR: str = os.path.join(DATA_DIR, "task_backups") # 备份目录
|
||
TASK_SCHEDULER_MAX_BACKUPS: int = 5 # 最大备份数
|
||
TASK_SCHEDULER_ZOMBIE_TASK_CHECK_INTERVAL: int = 60 # 僵尸任务检查间隔(秒)
|
||
TASK_SCHEDULER_CPU_THRESHOLD: float = 80.0 # CPU使用率阈值(百分比)
|
||
TASK_SCHEDULER_MEMORY_THRESHOLD: float = 80.0 # 内存使用率阈值(百分比)
|
||
TASK_SCHEDULER_AUTO_SCALE_INTERVAL: int = 120 # 自动扩缩容间隔(秒)
|
||
TASK_SCHEDULER_WORKER_HEARTBEAT_INTERVAL: int = 120 # 心跳间隔(秒)
|
||
|
||
@property
|
||
def DATABASE_URL(self) -> str:
|
||
"""构建数据库连接URL"""
|
||
if self.DB_DIALECT == 'sqlite':
|
||
return f"sqlite:///{self.DB_NAME}"
|
||
return f"{self.DB_DIALECT}+{self.DB_DRIVER}://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}?charset={self.DB_CHARSET}"
|
||
|
||
@property
|
||
def DATABASE_ARGS(self) -> Dict[str, Any]:
|
||
"""构建数据库连接参数"""
|
||
args = {
|
||
"pool_size": self.DB_POOL_SIZE,
|
||
"max_overflow": self.DB_MAX_OVERFLOW,
|
||
"pool_recycle": self.DB_POOL_RECYCLE,
|
||
"echo": self.DB_ECHO
|
||
}
|
||
|
||
return args
|
||
|
||
@property
|
||
def REDIS_URL(self) -> str:
|
||
"""构建Redis连接URL"""
|
||
if self.REDIS_PASSWORD:
|
||
return f"redis://:{self.REDIS_PASSWORD}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
|
||
return f"redis://{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
|
||
|
||
# 更新为Pydantic v2的配置方式
|
||
model_config = {
|
||
"env_file": ".env",
|
||
"env_file_encoding": "utf-8",
|
||
"case_sensitive": True
|
||
}
|
||
|
||
|
||
class DevelopmentConfig(BaseConfig):
|
||
"""开发环境配置"""
|
||
DEBUG: bool = True
|
||
DB_ECHO: bool = True # 开发环境输出SQL语句
|
||
LOG_LEVEL: str = "DEBUG"
|
||
SERVER_RELOAD: bool = True # 开发环境启用热重载
|
||
STORAGE_API_MOCK_MODE: bool = True # 开发环境默认使用API模拟模式
|
||
ROBOT_API_MOCK_MODE: bool = True # 开发环境默认使用机器人API模拟模式
|
||
|
||
|
||
# 根据环境变量选择配置
|
||
def get_config():
|
||
"""根据环境变量获取配置"""
|
||
return DevelopmentConfig()
|
||
|
||
# 导出配置
|
||
settings = get_config()
|
||
|
||
# 添加LogConfig类以供logger.py使用
|
||
class LogConfig:
|
||
"""日志配置类"""
|
||
@staticmethod
|
||
def as_dict():
|
||
"""返回日志配置字典"""
|
||
return {
|
||
"level": settings.LOG_LEVEL,
|
||
"file": settings.LOG_FILE,
|
||
"format": settings.LOG_FORMAT
|
||
} |