celery任务改为异步访问数据库

This commit is contained in:
mark.tian
2025-12-10 11:40:56 +08:00
parent d3d3502f5a
commit 572cc3113f
5 changed files with 456 additions and 213 deletions

View File

@@ -3,11 +3,10 @@
包含与回调处理相关的业务逻辑函数
"""
import json
import time
import asyncio
import httpx
from datetime import datetime
from typing import Optional, Tuple, Dict, Any
from sqlalchemy import text
from fastapi import Request
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings
@@ -95,8 +94,8 @@ async def log_callback_request(
return False
def save_callback_data_items(
conn,
async def save_callback_data_items(
db: AsyncSession,
callback_data_items: list,
callback_failure_log_id: int
) -> bool:
@@ -105,12 +104,14 @@ def save_callback_data_items(
Returns:
bool: 保存是否成功,True表示成功,False表示失败或跳过保存
"""
from sqlalchemy import text
try:
logger.info(f"📊 共传入callback_log_id {callback_failure_log_id} 的 {len(callback_data_items)} 条数据")
# 检查是否已经存在该callback_log_id的数据
existing_data_result = conn.execute(
existing_data_result = await db.execute(
text("SELECT * FROM callback_failure_data WHERE callback_failure_log_id = :log_id"),
{"log_id": callback_failure_log_id}
)
@@ -157,7 +158,7 @@ def save_callback_data_items(
raw_data_json = json.dumps(item, ensure_ascii=False)
# 直接插入数据库
conn.execute(
await db.execute(
text("""
INSERT INTO callback_failure_data
(callback_failure_log_id, phone_number, task_id, user_id, status, status_description, raw_data, calldate)
@@ -175,17 +176,18 @@ def save_callback_data_items(
}
)
conn.commit()
await db.commit()
logger.info(f"✅ 成功保存 {len(callback_data_items)} 条callback_data记录到数据库")
return True
except Exception as e:
logger.error(f"❌ 保存callback_data到数据库失败: {e}", exc_info=True)
await db.rollback()
# 不重新抛出异常,避免影响主业务流程
return False
def get_uncompleted_callback_log(conn) -> Tuple[bool, Optional[Tuple[int, str, str, str]]]:
async def get_uncompleted_callback_log(db: AsyncSession) -> Tuple[bool, Optional[Tuple[int, str, str, str]]]:
"""获取一条未完成的回调请求(按创建时间取最小值)
Returns:
@@ -193,9 +195,11 @@ def get_uncompleted_callback_log(conn) -> Tuple[bool, Optional[Tuple[int, str, s
- 第一个值表示查询是否成功(True表示成功,False表示失败)
- 第二个值为回调日志数据元组或None
"""
from sqlalchemy import text
try:
# 查询一条未完成的回调日志(按创建时间升序排列,取第一条)
result = conn.execute(
result = await db.execute(
text("""
SELECT id, site_id, request_headers, request_body
FROM callback_failure_logs
@@ -221,11 +225,13 @@ def get_uncompleted_callback_log(conn) -> Tuple[bool, Optional[Tuple[int, str, s
return False, None
def get_callback_log_data(conn, callback_log_id: int) -> Tuple[bool, Optional[str], Optional[str]]:
async def get_callback_log_data(db: AsyncSession, callback_log_id: int) -> Tuple[bool, Optional[str], Optional[str]]:
"""获取回调日志数据"""
from sqlalchemy import text
try:
# 查询回调日志
result = conn.execute(
result = await db.execute(
text("SELECT request_headers, request_body FROM callback_failure_logs WHERE id = :log_id"),
{"log_id": callback_log_id}
)
@@ -245,8 +251,8 @@ def get_callback_log_data(conn, callback_log_id: int) -> Tuple[bool, Optional[st
return False, None, None
def call_external_api_with_retry(
conn,
async def call_external_api_with_retry(
db: AsyncSession,
request_body: dict,
request_headers: Dict[str, str],
max_retries: int,
@@ -257,16 +263,16 @@ def call_external_api_with_retry(
try:
logger.info(f"🌐 尝试调用外部API接口,第{attempt}次")
with httpx.Client(timeout=30.0) as client:
response = client.post(
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(
settings.external_api_url,
json=request_body,
headers=request_headers
)
# 记录推送日志
_log_dtc_push_call(
conn=conn,
await _log_dtc_push_call(
db=db,
callback_failure_log_id=callback_failure_log_id,
request_url=settings.external_api_url,
request_headers=request_headers,
@@ -297,18 +303,20 @@ def call_external_api_with_retry(
# 如果不是最后一次尝试,等待一段时间再重试
if attempt < max_retries:
time.sleep(2 ** attempt) # 指数退避
await asyncio.sleep(2 ** attempt) # 指数退避
# 所有重试都失败了
logger.error(f"❌ 调用外部API接口失败,已重试{max_retries}次")
return False, max_retries
def mark_callback_log_completed(conn, callback_log_id: int) -> bool:
async def mark_callback_log_completed(db: AsyncSession, callback_log_id: int) -> bool:
"""标记CallbackFailureLog记录为已完成"""
from sqlalchemy import text
try:
# 先检查推送日志中是否有响应成功的记录
success_result = conn.execute(
success_result = await db.execute(
text("""
SELECT COUNT(*) as success_count
FROM external_api_logs
@@ -326,7 +334,7 @@ def mark_callback_log_completed(conn, callback_log_id: int) -> bool:
logger.info(f"✅ 回调日志 {callback_log_id} 找到 {success_count} 条成功推送记录,开始标记为完成")
# 更新指定日志记录为已完成
result = conn.execute(
result = await db.execute(
text("""
UPDATE callback_failure_logs
SET is_completed = true
@@ -341,18 +349,18 @@ def mark_callback_log_completed(conn, callback_log_id: int) -> bool:
logger.warning(f"⚠️ 回调日志 {callback_log_id} 已标记为完成或不存在")
return False
conn.commit()
await db.commit()
logger.info(f"✅ 回调日志 {callback_log_id} 已标记为完成")
return True
except Exception as e:
logger.error(f"❌ 标记回调日志 {callback_log_id} 完成失败: {e}", exc_info=True)
conn.rollback()
await db.rollback()
return False
def get_related_records_by_unique_data_list(
conn,
async def get_related_records_by_unique_data_list(
db: AsyncSession,
unique_data_list: list,
callback_log_id: int,
limit_count: int
@@ -360,7 +368,7 @@ def get_related_records_by_unique_data_list(
"""根据unique_data_list中的数据查询相关记录,按创建时间排序
Args:
conn: 数据库连接
db: 异步数据库会话
unique_data_list: 包含手机号、task_id、user_id的数据项列表
callback_log_id: 回调日志ID,作为过滤条件
limit_count: 获取记录数量限制
@@ -370,6 +378,8 @@ def get_related_records_by_unique_data_list(
- 第一个值表示查询是否成功(True表示成功,False表示失败)
- 第二个值为查询到的相关记录列表,失败时返回空列表
"""
from sqlalchemy import text
related_records = []
try:
@@ -387,7 +397,7 @@ def get_related_records_by_unique_data_list(
user_id = item.get('user_id', '')
if phone_number and task_id and user_id:
result = conn.execute(
result = await db.execute(
text("""
SELECT phone_number, task_id, user_id, created_at
FROM callback_failure_data
@@ -427,8 +437,8 @@ def get_related_records_by_unique_data_list(
return False, []
def _log_dtc_push_call(
conn,
async def _log_dtc_push_call(
db: AsyncSession,
callback_failure_log_id: int,
request_url: str,
request_headers: Dict[str, Any],
@@ -439,6 +449,8 @@ def _log_dtc_push_call(
retry_count: int
) -> bool:
"""记录DTC推送调用日志"""
from sqlalchemy import text
try:
# 提取手机号从请求体中
phone_number = None
@@ -448,7 +460,7 @@ def _log_dtc_push_call(
phone_number = first_item['number_data']['number']
# 记录到external_api_logs表
conn.execute(
await db.execute(
text("""
INSERT INTO external_api_logs (
callback_failure_log_id,
@@ -487,11 +499,11 @@ def _log_dtc_push_call(
}
)
conn.commit()
await db.commit()
logger.debug(f"📝 DTC推送调用日志记录成功,状态码: {response_status}")
return True
except Exception as e:
logger.error(f"❌ 记录DTC推送调用日志失败: {e}", exc_info=True)
conn.rollback()
await db.rollback()
return False