定时任务增加redis连接

This commit is contained in:
mark.tian
2025-12-09 08:05:45 +08:00
parent e146dfaadf
commit 6853624bd2
3 changed files with 323 additions and 177 deletions

View File

@@ -34,10 +34,14 @@ def push_data_to_dtc_task(self):
task_name = 'push_data_to_dtc' task_name = 'push_data_to_dtc'
logger.info(f"🌿 开始推送数据给DTC任务") logger.info(f"🌿 开始推送数据给DTC任务")
# 获取分布式锁,使用任务名称作为锁标识
lock = redis_manager.create_lock(f"celery_task:{task_name}", timeout=300) # 5分钟超时
try: try:
# 获取分布式锁,使用任务名称作为锁标识
connection_success = redis_manager.connect()
if not connection_success:
logger.error(f"❌ Redis管理器连接失败,任务停止执行")
raise Exception("Redis连接失败")
lock = redis_manager.create_lock(f"celery_task:{task_name}", timeout=300) # 5分钟超时
# 尝试获取锁 # 尝试获取锁
if not lock.acquire(blocking=False): if not lock.acquire(blocking=False):
logger.warning(f"⚠️ 任务 {task_name} 正在执行中,跳过本次执行") logger.warning(f"⚠️ 任务 {task_name} 正在执行中,跳过本次执行")
@@ -45,14 +49,15 @@ def push_data_to_dtc_task(self):
logger.info(f"🔒 成功获取任务 {task_name} 的分布式锁") logger.info(f"🔒 成功获取任务 {task_name} 的分布式锁")
try:
with engine.connect() as conn: with engine.connect() as conn:
logger.info("1")
# 更新任务状态 # 更新任务状态
self.update_state( self.update_state(
state='PROGRESS', state='PROGRESS',
meta={'current': 0, 'total': 100, 'status': f'正在获取下一条回调请求日志...'} meta={'current': 0, 'total': 100, 'status': f'正在获取下一条回调请求日志...'}
) )
logger.info("2")
# 获取一条未完成的回调请求(按创建时间取最小值) # 获取一条未完成的回调请求(按创建时间取最小值)
query_success, callback_log_data = get_uncompleted_callback_log(conn) query_success, callback_log_data = get_uncompleted_callback_log(conn)
if not query_success: if not query_success:
@@ -61,7 +66,7 @@ def push_data_to_dtc_task(self):
if not query_success: if not query_success:
logger.error("❌ 再次查询未完成的回调请求失败,停止任务执行") logger.error("❌ 再次查询未完成的回调请求失败,停止任务执行")
raise Exception("查询未完成的回调请求失败,任务停止执行") raise Exception("查询未完成的回调请求失败,任务停止执行")
logger.info("3")
if not callback_log_data: if not callback_log_data:
logger.info("📋 没有找到未完成的回调请求") logger.info("📋 没有找到未完成的回调请求")
return {"status": "skipped", "message": "没有找到未完成的回调请求"} return {"status": "skipped", "message": "没有找到未完成的回调请求"}
@@ -124,7 +129,6 @@ def push_data_to_dtc_task(self):
if len(unique_data_list) < original_count: if len(unique_data_list) < original_count:
logger.info(f"🗑️ 移除了 {original_count - len(unique_data_list)} 条重复数据 - callback_log_id: {callback_log_id}, site_id: {site_id}") logger.info(f"🗑️ 移除了 {original_count - len(unique_data_list)} 条重复数据 - callback_log_id: {callback_log_id}, site_id: {site_id}")
# 查询相关数据:根据手机号、task_id、user_id作为条件,按创建时间排序获取前三条记录 # 查询相关数据:根据手机号、task_id、user_id作为条件,按创建时间排序获取前三条记录
query_success, related_records = get_related_records_by_unique_data_list( query_success, related_records = get_related_records_by_unique_data_list(
conn, unique_data_list, callback_log_id, settings.count_threshold conn, unique_data_list, callback_log_id, settings.count_threshold
@@ -188,18 +192,15 @@ def push_data_to_dtc_task(self):
} }
except Exception as e: except Exception as e:
logger.error(f"❌ 推送数据给DTC时发生错误: {e}", exc_info=True) logger.error(f"❌ 任务执行失败: {e}", exc_info=True)
return {"status": "error", "message": str(e)} return {"status": "error", "message": str(e)}
finally: finally:
# 释放分布式锁 # 释放分布式锁
try: try:
if 'lock' in locals():
lock.release() lock.release()
logger.info(f"🔓 释放任务 {task_name} 的分布式锁") logger.info(f"🔓 释放任务 {task_name} 的分布式锁")
except Exception as e: except Exception as e:
logger.error(f"❌ 释放任务 {task_name} 的分布式锁失败: {e}") logger.error(f"❌ 释放任务 {task_name} 的分布式锁失败: {e}")
except Exception as e:
logger.error(f"❌ 获取分布式锁失败: {e}", exc_info=True)
return {"status": "error", "message": f"获取分布式锁失败: {str(e)}"}

View File

@@ -1,5 +1,4 @@
import redis.asyncio as redis import redis
import asyncio
import uuid import uuid
from typing import Optional from typing import Optional
from app.config import settings from app.config import settings
@@ -9,6 +8,7 @@ logger = get_redis_logger()
class RedisLock: class RedisLock:
"""Redis分布式锁"""
def __init__(self, redis_client: redis.Redis, key: str, timeout: int = None): def __init__(self, redis_client: redis.Redis, key: str, timeout: int = None):
self.redis_client = redis_client self.redis_client = redis_client
self.key = f"lock:{key}" self.key = f"lock:{key}"
@@ -16,7 +16,7 @@ class RedisLock:
self.identifier = str(uuid.uuid4()) self.identifier = str(uuid.uuid4())
self.acquired = False self.acquired = False
async def acquire(self) -> bool: def acquire(self, blocking: bool = True, timeout: int = None) -> bool:
"""获取分布式锁""" """获取分布式锁"""
logger.debug(f"🔒 尝试获取Redis锁: {self.key}") logger.debug(f"🔒 尝试获取Redis锁: {self.key}")
@@ -28,7 +28,7 @@ class RedisLock:
end end
""" """
result = await self.redis_client.eval( result = self.redis_client.eval(
lua_script, lua_script,
1, 1,
self.key, self.key,
@@ -44,7 +44,7 @@ class RedisLock:
return self.acquired return self.acquired
async def release(self) -> bool: def release(self) -> bool:
"""释放分布式锁""" """释放分布式锁"""
if not self.acquired: if not self.acquired:
return False return False
@@ -57,7 +57,7 @@ class RedisLock:
end end
""" """
result = await self.redis_client.eval( result = self.redis_client.eval(
lua_script, lua_script,
1, 1,
self.key, self.key,
@@ -67,39 +67,58 @@ class RedisLock:
self.acquired = False self.acquired = False
return bool(result) return bool(result)
async def __aenter__(self): def __enter__(self):
"""异步上下文管理器入口""" """同步上下文管理器入口"""
retries = 0 retries = 0
while retries < settings.redis_lock_max_retries: while retries < settings.redis_lock_max_retries:
if await self.acquire(): if self.acquire(blocking=False):
return self return self
await asyncio.sleep(settings.redis_lock_retry_delay) import time
time.sleep(settings.redis_lock_retry_delay)
retries += 1 retries += 1
raise TimeoutError(f"Failed to acquire lock {self.key} after {retries} retries") raise TimeoutError(f"Failed to acquire lock {self.key} after {retries} retries")
async def __aexit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
"""异步上下文管理器出口""" """同步上下文管理器出口"""
await self.release() self.release()
class RedisManager: class RedisManager:
def __init__(self): def __init__(self):
self.redis_client: Optional[redis.Redis] = None self.redis_client: Optional[redis.Redis] = None
async def connect(self): def connect(self) -> bool:
"""连接Redis""" """连接Redis
Returns:
bool: 连接是否成功
"""
try:
logger.info(f"🔴 正在连接Redis: {settings.redis_url}")
self.redis_client = redis.from_url( self.redis_client = redis.from_url(
settings.redis_url, settings.redis_url,
encoding="utf-8", encoding="utf-8",
decode_responses=True decode_responses=True,
socket_connect_timeout=5,
socket_timeout=5,
retry_on_timeout=True
) )
await self.redis_client.ping() result = self.redis_client.ping()
if result:
logger.info("✅ Redis连接成功")
return True
else:
logger.error("❌ Redis ping失败")
return False
except Exception as e:
logger.error(f"❌ Redis连接失败: {e}")
return False
async def disconnect(self): def disconnect(self):
"""断开Redis连接""" """断开Redis连接"""
if self.redis_client: if self.redis_client:
await self.redis_client.close() self.redis_client.close()
def create_lock(self, key: str, timeout: int = None) -> RedisLock: def create_lock(self, key: str, timeout: int = None) -> RedisLock:
"""创建分布式锁""" """创建分布式锁"""

View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python3
"""
测试RedisManager连接功能
验证connect方法的返回值
"""
from app.redis_lock import redis_manager
from app.logger import get_redis_logger
logger = get_redis_logger()
def test_connection():
"""测试连接"""
logger.info("🧪 测试Redis连接...")
# 测试连接
success = redis_manager.connect()
if success:
logger.info("✅ 连接成功")
# 测试创建锁
try:
lock = redis_manager.create_lock("test:lock", timeout=10)
logger.info("✅ 锁创建成功")
# 尝试获取锁
acquired = lock.acquire(blocking=False)
if acquired:
logger.info("✅ 锁获取成功")
# 释放锁
released = lock.release()
if released:
logger.info("✅ 锁释放成功")
else:
logger.error("❌ 锁释放失败")
return False
else:
logger.error("❌ 锁获取失败")
return False
except Exception as e:
logger.error(f"❌ 锁操作失败: {e}")
return False
else:
logger.error("❌ 连接失败")
return False
return True
def test_connection_failures():
"""测试连接失败场景"""
logger.info("🧪 测试连接失败处理...")
# 直接测试连接一个不存在的主机
from app.config import settings
original_url = settings.redis_url
try:
# 创建一个新的RedisManager实例用于测试失败场景
from app.redis_lock import RedisManager
test_manager = RedisManager()
# 模拟连接失败 - 直接使用无效的URL
import redis
invalid_redis_client = redis.from_url(
"redis://invalid_host:6379/0",
encoding="utf-8",
decode_responses=True,
socket_connect_timeout=1,
socket_timeout=1
)
test_manager.redis_client = invalid_redis_client
# 尝试ping,这应该会失败
try:
result = test_manager.redis_client.ping()
logger.error("❌ 连接应该失败但成功了")
return False
except Exception:
logger.info("✅ 连接失败处理正确")
return True
except Exception as e:
logger.info("✅ 连接失败处理正确")
return True
def main():
"""主函数"""
logger.info("🚀 开始RedisManager连接测试")
# 测试1: 连接
logger.info("\n" + "="*50)
logger.info("测试1: 连接")
logger.info("="*50)
connection_success = test_connection()
# 测试2: 连接失败处理
logger.info("\n" + "="*50)
logger.info("测试2: 连接失败处理")
logger.info("="*50)
failure_success = test_connection_failures()
# 断开连接
redis_manager.disconnect()
logger.info("🔌 Redis连接已断开")
# 总结
logger.info("\n" + "="*50)
logger.info("测试结果总结")
logger.info("="*50)
if connection_success and failure_success:
logger.info("🎉 所有测试通过!RedisManager连接功能正常")
return True
else:
logger.error("❌ 部分测试失败,请检查实现")
return False
if __name__ == "__main__":
success = main()
exit(0 if success else 1)