docs: 移动蓝绿部署指南到 troubleshooting 目录

This commit is contained in:
Simon
2026-07-05 17:03:36 +08:00
parent ab90db3d3d
commit ca7c6d937a
91 changed files with 4841 additions and 406 deletions
+50 -11
View File
@@ -12,7 +12,7 @@
import logging
from datetime import datetime
from typing import List, Optional
from typing import Any, List, Optional
from uuid import UUID
from sqlalchemy import and_, case, desc, func, select
@@ -43,15 +43,18 @@ class SessionService:
self,
db: AsyncSession,
wecom_service: Optional[WecomService] = None,
redis_client: Optional[Any] = None,
):
"""初始化会话状态管理服务。
Args:
db: 异步数据库会话
wecom_service: 企微 API 服务(用于坐席接入时发送通知,可选)
redis_client: Redis客户端(用于头像缓存,可选)
"""
self.db = db
self.wecom_service = wecom_service
self.redis_client = redis_client
# --------------------------------------------------------------------------
# 创建会话
@@ -819,12 +822,16 @@ class SessionService:
# 邀请功能(P0-09~P0-11):坐席邀请员工/部门加入会话
# ======================================================================
async def _get_employee_avatar(self, employee_id: str) -> str:
"""获取员工头像URL。
# 头像缓存 TTL7天
AVATAR_CACHE_TTL = 7 * 24 * 60 * 60
做什么:从 employees 表或企微通讯录API获取头像
为什么:邀请参与者时需要展示头像,前端无法单独获取被邀请人头像
优先级:employees 表(本地缓存) > 企微API(实时获取)
async def _get_employee_avatar(self, employee_id: str) -> str:
"""获取员工头像URL(带Redis缓存)。
优先级:
1. Redis 缓存(最快)
2. employees 表
3. 企微API(获取后存入Redis缓存)
Args:
employee_id: 企微员工UserID
@@ -832,25 +839,57 @@ class SessionService:
Returns:
str: 头像URL,获取不到返回空字符串
"""
# 1. 优先从 employees 表查(本地缓存,速度快)
cache_key = f"employee:avatar:{employee_id}"
# 1. 优先从 Redis 缓存获取
if self.redis_client:
try:
cached_avatar = await self.redis_client.get(cache_key)
if cached_avatar:
logger.debug(f"从Redis缓存获取头像: employee_id={employee_id}")
return cached_avatar.decode("utf-8") if isinstance(cached_avatar, bytes) else cached_avatar
except Exception as e:
logger.warning(f"从Redis获取头像缓存失败: employee_id={employee_id}, error={e}")
# 2. 从 employees 表获取(需要匹配 corp_id
from app.models.employee import Employee
from app.core.config import settings
result = await self.db.execute(
select(Employee.avatar).where(Employee.employee_id == employee_id)
select(Employee.avatar).where(
Employee.employee_id == employee_id,
Employee.corp_id == settings.wecom_corp_id
)
)
row = result.first()
if row and row[0]:
logger.info(f"从employees表获取头像: employee_id={employee_id}, avatar={row[0][:50]}...")
# 存入 Redis 缓存
if self.redis_client:
try:
await self.redis_client.setex(cache_key, self.AVATAR_CACHE_TTL, row[0])
except Exception as e:
logger.warning(f"存入Redis头像缓存失败: employee_id={employee_id}, error={e}")
return row[0]
else:
logger.info(f"employees表无头像记录: employee_id={employee_id}")
# 2. employees 表没有,尝试从企微通讯录API获取
# 3. employees 表没有,尝试从企微通讯录API获取
avatar = ""
if self.wecom_service:
try:
user_info = await self.wecom_service.get_user_info(employee_id)
avatar = user_info.get("avatar", "")
return avatar
logger.info(f"企微API返回头像: employee_id={employee_id}, avatar={'有值(' + str(len(avatar)) + '字符)' if avatar else ''}")
# 存入 Redis 缓存(即使为空也缓存,避免频繁请求API)
if self.redis_client and avatar:
try:
await self.redis_client.setex(cache_key, self.AVATAR_CACHE_TTL, avatar)
except Exception as e:
logger.warning(f"存入Redis头像缓存失败: employee_id={employee_id}, error={e}")
except Exception as e:
logger.warning(f"从企微API获取头像失败: employee_id={employee_id}, error={e}")
return ""
return avatar
async def invite_participants(
self,