feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,452 @@
|
||||
"""
|
||||
数据库连接池管理模块
|
||||
|
||||
提供数据库连接池的创建、管理和监控功能。
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import uuid
|
||||
from typing import Any, Dict, List, Optional, Callable
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
import queue
|
||||
|
||||
|
||||
class ConnectionStatus(Enum):
|
||||
"""连接状态"""
|
||||
IDLE = "idle"
|
||||
ACTIVE = "active"
|
||||
CLOSED = "closed"
|
||||
UNHEALTHY = "unhealthy"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Connection:
|
||||
"""数据库连接封装"""
|
||||
id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
||||
status: ConnectionStatus = ConnectionStatus.IDLE
|
||||
created_at: float = field(default_factory=time.time)
|
||||
last_used: float = field(default_factory=time.time)
|
||||
use_count: int = 0
|
||||
host: str = ""
|
||||
port: int = 3306
|
||||
database: str = ""
|
||||
user: str = ""
|
||||
password: str = ""
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
"""检查连接是否有效"""
|
||||
return self.status in [ConnectionStatus.IDLE, ConnectionStatus.ACTIVE]
|
||||
|
||||
def execute(self, query: str) -> Any:
|
||||
"""执行查询(模拟)"""
|
||||
if not self.is_valid():
|
||||
raise Exception("连接无效")
|
||||
return f"Result of: {query}"
|
||||
|
||||
def close(self) -> None:
|
||||
"""关闭连接"""
|
||||
self.status = ConnectionStatus.CLOSED
|
||||
|
||||
|
||||
class ConnectionPool:
|
||||
"""
|
||||
数据库连接池
|
||||
|
||||
特性:
|
||||
- 支持最小/最大连接数配置
|
||||
- 支持连接超时等待
|
||||
- 支持健康检查
|
||||
- 支持自动扩容
|
||||
- 线程安全
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
min_connections: int = 2,
|
||||
max_connections: int = 10,
|
||||
host: str = "localhost",
|
||||
port: int = 3306,
|
||||
database: str = "",
|
||||
user: str = "",
|
||||
password: str = "",
|
||||
connection_timeout: int = 30,
|
||||
health_check_interval: int = 60,
|
||||
auto_scale: bool = False
|
||||
):
|
||||
"""
|
||||
初始化连接池
|
||||
|
||||
Args:
|
||||
min_connections: 最小连接数
|
||||
max_connections: 最大连接数
|
||||
host: 数据库主机
|
||||
port: 数据库端口
|
||||
database: 数据库名
|
||||
user: 用户名
|
||||
password: 密码
|
||||
connection_timeout: 连接超时时间(秒)
|
||||
health_check_interval: 健康检查间隔(秒)
|
||||
auto_scale: 是否自动扩容
|
||||
"""
|
||||
self._min_connections = min_connections
|
||||
self._max_connections = max_connections
|
||||
self._host = host
|
||||
self._port = port
|
||||
self._database = database
|
||||
self._user = user
|
||||
self._password = password
|
||||
self._connection_timeout = connection_timeout
|
||||
self._health_check_interval = health_check_interval
|
||||
self._auto_scale = auto_scale
|
||||
|
||||
# 连接池
|
||||
self._idle_connections: queue.Queue[Connection] = queue.Queue()
|
||||
self._active_connections: Dict[str, Connection] = {}
|
||||
self._all_connections: Dict[str, Connection] = {}
|
||||
|
||||
# 锁
|
||||
self._lock = threading.RLock()
|
||||
self._condition = threading.Condition(self._lock)
|
||||
|
||||
# 统计信息
|
||||
self._stats = {
|
||||
"total_get_count": 0,
|
||||
"total_release_count": 0,
|
||||
"total_wait_count": 0,
|
||||
"total_wait_time": 0.0,
|
||||
"health_check_count": 0,
|
||||
"unhealthy_count": 0,
|
||||
}
|
||||
|
||||
# 健康检查线程
|
||||
self._health_check_thread: Optional[threading.Thread] = None
|
||||
self._shutdown = False
|
||||
|
||||
# 初始化最小连接数
|
||||
self._initialize_min_connections()
|
||||
|
||||
# 启动健康检查
|
||||
if health_check_interval > 0:
|
||||
self._start_health_check()
|
||||
|
||||
def _initialize_min_connections(self) -> None:
|
||||
"""初始化最小连接数"""
|
||||
for _ in range(self._min_connections):
|
||||
conn = self._create_connection()
|
||||
self._idle_connections.put(conn)
|
||||
self._all_connections[conn.id] = conn
|
||||
|
||||
def _create_connection(self) -> Connection:
|
||||
"""创建新连接"""
|
||||
conn = Connection(
|
||||
host=self._host,
|
||||
port=self._port,
|
||||
database=self._database,
|
||||
user=self._user,
|
||||
password=self._password
|
||||
)
|
||||
return conn
|
||||
|
||||
def get_connection(self, timeout: Optional[int] = None) -> Connection:
|
||||
"""
|
||||
获取连接
|
||||
|
||||
Args:
|
||||
timeout: 超时时间(秒),None表示使用默认值
|
||||
|
||||
Returns:
|
||||
数据库连接
|
||||
|
||||
Raises:
|
||||
Exception: 超时或连接池已关闭
|
||||
"""
|
||||
if timeout is None:
|
||||
timeout = self._connection_timeout
|
||||
|
||||
with self._condition:
|
||||
self._stats["total_get_count"] += 1
|
||||
|
||||
# 尝试获取空闲连接
|
||||
while not self._shutdown:
|
||||
# 如果有空闲连接,直接返回
|
||||
try:
|
||||
conn = self._idle_connections.get_nowait()
|
||||
if conn.is_valid():
|
||||
conn.status = ConnectionStatus.ACTIVE
|
||||
conn.last_used = time.time()
|
||||
conn.use_count += 1
|
||||
self._active_connections[conn.id] = conn
|
||||
return conn
|
||||
else:
|
||||
# 连接无效,移除
|
||||
self._remove_connection(conn)
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
# 如果没有空闲连接,尝试创建新连接
|
||||
if len(self._all_connections) < self._max_connections:
|
||||
conn = self._create_connection()
|
||||
conn.status = ConnectionStatus.ACTIVE
|
||||
conn.last_used = time.time()
|
||||
conn.use_count += 1
|
||||
self._active_connections[conn.id] = conn
|
||||
self._all_connections[conn.id] = conn
|
||||
return conn
|
||||
|
||||
# 如果达到最大连接数,等待
|
||||
self._stats["total_wait_count"] += 1
|
||||
start_wait = time.time()
|
||||
|
||||
if not self._condition.wait(timeout=timeout):
|
||||
raise Exception(f"获取连接超时({timeout}秒)")
|
||||
|
||||
self._stats["total_wait_time"] += time.time() - start_wait
|
||||
|
||||
raise Exception("连接池已关闭")
|
||||
|
||||
def release_connection(self, conn: Connection) -> None:
|
||||
"""
|
||||
释放连接
|
||||
|
||||
Args:
|
||||
conn: 要释放的连接
|
||||
"""
|
||||
with self._condition:
|
||||
if conn.id in self._active_connections:
|
||||
del self._active_connections[conn.id]
|
||||
|
||||
if conn.is_valid():
|
||||
conn.status = ConnectionStatus.IDLE
|
||||
conn.last_used = time.time()
|
||||
self._idle_connections.put(conn)
|
||||
self._stats["total_release_count"] += 1
|
||||
else:
|
||||
# 连接无效,移除
|
||||
self._remove_connection(conn)
|
||||
|
||||
# 通知等待的线程
|
||||
self._condition.notify()
|
||||
|
||||
def _remove_connection(self, conn: Connection) -> None:
|
||||
"""移除连接"""
|
||||
conn.close()
|
||||
if conn.id in self._all_connections:
|
||||
del self._all_connections[conn.id]
|
||||
if conn.id in self._active_connections:
|
||||
del self._active_connections[conn.id]
|
||||
|
||||
def close(self) -> None:
|
||||
"""关闭连接池"""
|
||||
self._shutdown = True
|
||||
|
||||
with self._condition:
|
||||
# 关闭所有连接
|
||||
for conn in self._all_connections.values():
|
||||
conn.close()
|
||||
|
||||
self._all_connections.clear()
|
||||
self._active_connections.clear()
|
||||
|
||||
# 清空空闲队列
|
||||
while not self._idle_connections.empty():
|
||||
try:
|
||||
self._idle_connections.get_nowait()
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
# 通知所有等待的线程
|
||||
self._condition.notify_all()
|
||||
|
||||
def get_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取统计信息
|
||||
|
||||
Returns:
|
||||
统计信息字典
|
||||
"""
|
||||
with self._lock:
|
||||
return {
|
||||
"total_connections": len(self._all_connections),
|
||||
"idle_connections": self._idle_connections.qsize(),
|
||||
"active_connections": len(self._active_connections),
|
||||
"min_connections": self._min_connections,
|
||||
"max_connections": self._max_connections,
|
||||
"total_get_count": self._stats["total_get_count"],
|
||||
"total_release_count": self._stats["total_release_count"],
|
||||
"total_wait_count": self._stats["total_wait_count"],
|
||||
"total_wait_time": self._stats["total_wait_time"],
|
||||
"health_check_count": self._stats["health_check_count"],
|
||||
"unhealthy_count": self._stats["unhealthy_count"],
|
||||
}
|
||||
|
||||
def health_check(self) -> bool:
|
||||
"""
|
||||
执行健康检查
|
||||
|
||||
Returns:
|
||||
是否所有连接都健康
|
||||
"""
|
||||
with self._lock:
|
||||
self._stats["health_check_count"] += 1
|
||||
|
||||
unhealthy_count = 0
|
||||
for conn in list(self._all_connections.values()):
|
||||
if not conn.is_valid():
|
||||
unhealthy_count += 1
|
||||
self._remove_connection(conn)
|
||||
|
||||
self._stats["unhealthy_count"] += unhealthy_count
|
||||
|
||||
# 补充最小连接数
|
||||
while len(self._all_connections) < self._min_connections:
|
||||
conn = self._create_connection()
|
||||
self._idle_connections.put(conn)
|
||||
self._all_connections[conn.id] = conn
|
||||
|
||||
return unhealthy_count == 0
|
||||
|
||||
def get_health_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取健康统计
|
||||
|
||||
Returns:
|
||||
健康统计字典
|
||||
"""
|
||||
with self._lock:
|
||||
healthy = sum(1 for conn in self._all_connections.values() if conn.is_valid())
|
||||
unhealthy = len(self._all_connections) - healthy
|
||||
|
||||
return {
|
||||
"healthy_connections": healthy,
|
||||
"unhealthy_connections": unhealthy,
|
||||
"health_check_count": self._stats["health_check_count"],
|
||||
"total_unhealthy_count": self._stats["unhealthy_count"],
|
||||
}
|
||||
|
||||
def _start_health_check(self) -> None:
|
||||
"""启动健康检查线程"""
|
||||
def health_check_worker():
|
||||
while not self._shutdown:
|
||||
time.sleep(self._health_check_interval)
|
||||
if not self._shutdown:
|
||||
self.health_check()
|
||||
|
||||
self._health_check_thread = threading.Thread(
|
||||
target=health_check_worker,
|
||||
daemon=True
|
||||
)
|
||||
self._health_check_thread.start()
|
||||
|
||||
|
||||
class ConnectionPoolManager:
|
||||
"""
|
||||
连接池管理器
|
||||
|
||||
单例模式管理多个命名连接池
|
||||
"""
|
||||
|
||||
_instance = None
|
||||
_lock = threading.Lock()
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
with cls._lock:
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
cls._instance._pools = {}
|
||||
return cls._instance
|
||||
|
||||
def create_pool(
|
||||
self,
|
||||
name: str,
|
||||
min_connections: int = 2,
|
||||
max_connections: int = 10,
|
||||
host: str = "localhost",
|
||||
port: int = 3306,
|
||||
database: str = "",
|
||||
user: str = "",
|
||||
password: str = "",
|
||||
**kwargs
|
||||
) -> ConnectionPool:
|
||||
"""
|
||||
创建命名连接池
|
||||
|
||||
Args:
|
||||
name: 连接池名称
|
||||
min_connections: 最小连接数
|
||||
max_connections: 最大连接数
|
||||
host: 数据库主机
|
||||
port: 数据库端口
|
||||
database: 数据库名
|
||||
user: 用户名
|
||||
password: 密码
|
||||
**kwargs: 其他参数
|
||||
|
||||
Returns:
|
||||
连接池实例
|
||||
"""
|
||||
if name in self._pools:
|
||||
return self._pools[name]
|
||||
|
||||
pool = ConnectionPool(
|
||||
min_connections=min_connections,
|
||||
max_connections=max_connections,
|
||||
host=host,
|
||||
port=port,
|
||||
database=database,
|
||||
user=user,
|
||||
password=password,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
self._pools[name] = pool
|
||||
return pool
|
||||
|
||||
def get_pool(self, name: str) -> Optional[ConnectionPool]:
|
||||
"""
|
||||
获取命名连接池
|
||||
|
||||
Args:
|
||||
name: 连接池名称
|
||||
|
||||
Returns:
|
||||
连接池实例,不存在则返回None
|
||||
"""
|
||||
return self._pools.get(name)
|
||||
|
||||
def remove_pool(self, name: str) -> bool:
|
||||
"""
|
||||
移除连接池
|
||||
|
||||
Args:
|
||||
name: 连接池名称
|
||||
|
||||
Returns:
|
||||
是否成功移除
|
||||
"""
|
||||
if name in self._pools:
|
||||
self._pools[name].close()
|
||||
del self._pools[name]
|
||||
return True
|
||||
return False
|
||||
|
||||
def close_all(self) -> None:
|
||||
"""关闭所有连接池"""
|
||||
for pool in self._pools.values():
|
||||
pool.close()
|
||||
self._pools.clear()
|
||||
|
||||
def get_all_stats(self) -> Dict[str, Dict[str, Any]]:
|
||||
"""
|
||||
获取所有连接池统计
|
||||
|
||||
Returns:
|
||||
连接池名称到统计信息的映射
|
||||
"""
|
||||
return {name: pool.get_stats() for name, pool in self._pools.items()}
|
||||
|
||||
|
||||
# 全局连接池管理器实例
|
||||
pool_manager = ConnectionPoolManager()
|
||||
Reference in New Issue
Block a user