Python中单独使用Celery和Django ORM时,celery worker process会复制main process的数据库连接吗?
Django 的版本是 1.7, 使用了 django-celery 3.1.17. 直接运行celery worker -l info -A project_name开始执行, 任务并不需要通过请求触发. 其中的 Django 某个 App 的tasks.py定义为
# encoding: utf-8
from __future__ import absolute_import
from some_django_app.celery import app
from .services import use_orm
@app.task
def test():
print ‘Test succeed’
@app.task
def do_some():
use_orm
do_some.delay()
是否在执行 celery worker -l info -A project_name 时创建的数据库连接先由Main process建立, 然后再生成celery worker process, 从而多个celery worker process共用一个数据库连接?
Python中单独使用Celery和Django ORM时,celery worker process会复制main process的数据库连接吗?
Django 没有使用连接池而是持久化, 所以只有你对数据库操作时才会建立数据库链接,刚建立进程时是没有数据库连接的。即使有连接池,进程之间资源也不共享,子进程只是父进程的 copy,并不共享内存,所以你程序中有操作数据库的话,还是一个进程会占用一个连接。
在Django项目中单独使用Celery(不通过django-celery-results等集成包),Celery worker进程不会直接复制主进程的数据库连接。每个worker进程会独立建立自己的数据库连接池。
关键点在于Django的数据库连接是线程局部的(thread-local),而Celery worker是多进程模型。当worker启动时,它会加载Django配置并初始化自己的连接。这意味着:
- 主进程(启动Celery的进程)的连接与worker进程的连接完全独立
- 每个worker进程有自己的连接池
- 连接生命周期由worker进程管理,不会跨进程共享
如果你在任务中直接使用Django ORM,典型的配置是这样的:
# celery.py
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
app = Celery('project')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
from django.db import connection
print(f"Worker PID: {os.getpid()}, Connection: {id(connection)}")
运行worker时,每个进程都会打印不同的连接ID,证明它们是独立的。
要确保连接正常关闭,可以在任务结束时调用connection.close(),或者配置Django的CONN_MAX_AGE来控制连接复用。
总结:Celery worker会自己建连接,不会复用主进程的。
我数据库设置的连接过期时间为 5 分钟, Django 的 Setting.py 中没有设置 MAX_CON_AGE(默认值是 0); 我在 use_orm 中起了一个 RabbitMQ 的消息队列的消费者(start_consuming), 收到消息并利用 ORM 保存数据库. 刚启动 Celery 的时候是正常的, 但是过了 5 分钟后, 再从消息队列接收到消息时, 就会出现 MySQL server has gone away 的错误. 这为啥呢? 能说说你的想法么
独立进程需要手动手动管理数据库关闭。在你使用 orm 的函数起始位置加上 close_old_connections() 例如:<br>from django.db import close_old_connections<br>def func_use_orm():<br> close_old_connections()<br> <br> ······<br> <br> close_old_connections()<br>
close_old_connections() 没有用, 使用connection.close()倒是能行

