使用Celery后Django Admin存对象时PostgreSQL报EOF错误排查
问题排查:Django Admin保存对象时PostgreSQL连接异常
现象说明
- Django Admin保存对象时,PostgreSQL日志抛出错误:
LOG: unexpected EOF on client connection with an open transaction - Django自身无任何日志或报错,但浏览器端出现错误(附图)
- 此前功能完全正常,引入Celery定时任务后出现该问题
相关代码
signals.py
@receiver(post_save, sender=Posts) def send_save_obj(sender, instance, created, **kwargs): # Translate to latin relates_to = instance title = to_latin(instance.title) author = instance.author ... # Creating latin obj if created and language == 'uz': def save_latn_obj(): # create latin post post = PostUzLatn.objects.create( relates_to=relates_to, title=title, ... ) post.tags.add(tags) transaction.on_commit(save_latn_obj) # Sending to telegram channel # Get the current time in the server's local time zone server_time = datetime.now() # Create a timezone object for Tashkent tashkent_tz = pytz.timezone('Asia/Tashkent') # Convert the server time to Tashkent time tashkent_time = server_time.astimezone(tashkent_tz) if 'tg' in instance.social_network \ and publish <= tashkent_time: send_news( title=instance.title, ) # Update status after sending msg Posts.objects.filter(id=instance.id).update(is_sent=["is_sent_tg",]) # Delete the cache key to invalidate the cache for this view cache.clear()
bot.py
def send_news(title): if tizer: bot.send_video(CHANNEL_ID, video=tizer, caption=title, supports_streaming=True) else: bot.send_photo(CHANNEL_ID, image, caption=title)
可能原因及修复方向
1. 耗时操作阻塞事务导致连接断开
send_news是同步执行的网络请求(调用Telegram API),如果API响应慢,会长时间阻塞当前请求的数据库事务。PostgreSQL会因客户端长时间无响应,主动断开未完成事务的连接,触发unexpected EOF错误。
修复:
把send_news改为Celery异步任务,避免在信号函数内同步阻塞:
# signals.py中替换原send_news调用 from .tasks import send_news_task send_news_task.delay(title=instance.title)
新建tasks.py定义异步任务:
from celery import shared_task from .bot import send_news @shared_task def send_news_task(title): send_news(title)
2. 事务内的更新操作引发冲突
Posts.objects.filter(id=instance.id).update(...)直接在post_save信号内执行,此时原事务尚未提交,可能引发锁冲突或连接生命周期异常。
修复:
把更新操作放到transaction.on_commit回调中,确保原事务提交后再执行:
# 替换原更新代码 def update_sent_status(): Posts.objects.filter(id=instance.id).update(is_sent=["is_sent_tg",]) transaction.on_commit(update_sent_status)
3. 时区处理逻辑不规范
使用datetime.now()获取非时区感知时间,可能导致时间判断逻辑异常,间接引发事务流程问题。
修复:
改用Django提供的时区感知时间工具:
from django.utils import timezone server_time = timezone.now() tashkent_tz = pytz.timezone('Asia/Tashkent') tashkent_time = server_time.astimezone(tashkent_tz)
4. Celery连接池干扰Django数据库连接
引入Celery后,worker的数据库连接池可能与Django的连接池发生冲突,导致连接泄漏或被提前回收。
检查配置:
确保Celery连接池参数合理,例如:
CELERY_BROKER_POOL_LIMIT = 10 CELERY_DB_REUSE_MAX = 50
内容的提问来源于stack exchange,提问作者mirodil
相关产品推荐
相关产品推荐

