Django+Celery+Scrapy架构遇ReactorNotRestartable及数据库SSL错误求助
解决Django+Celery+Scrapy组合中的ReactorNotRestartable与数据库SSL错误
嘿,我刚好踩过类似的坑,这俩问题确实挺磨人的,我给你一步步拆解解决:
一、搞定ReactorNotRestartable错误
这个问题的核心逻辑是:Celery是长生命周期进程,而Scrapy依赖的Twisted Reactor一旦启动并停止后,同一个进程里根本没法再次重启。当Celery重复调用你的自定义Django命令时,就会触发这个报错。
最优方案:用多进程隔离Scrapy运行环境
每次Celery任务触发时,启动一个全新的进程来执行Scrapy爬虫,这样每个进程的Reactor都是独立的,完全不会有重启冲突。给你两种实现方式:
方式1:Celery任务中用subprocess调用Django命令
from celery import shared_task import subprocess import sys @shared_task def scheduled_crawl_task(): # 用当前Python环境执行自定义命令,避免环境不一致问题 subprocess.run( [sys.executable, "manage.py", "get_data"], check=True, capture_output=True, text=True )
方式2:用multiprocessing封装命令调用
from celery import shared_task from multiprocessing import Process from django.core.management import call_command @shared_task def scheduled_crawl_task(): # 启动新进程执行爬虫命令 crawl_process = Process(target=call_command, args=("get_data",)) crawl_process.start() crawl_process.join()
备选方案:改用CrawlerRunner替代CrawlerProcess
如果你不想用多进程,也可以修改自定义命令里的Scrapy启动逻辑,用CrawlerRunner代替CrawlerProcess(它不会自动管理Reactor的启动/停止):
from scrapy.crawler import CrawlerRunner from scrapy.utils.log import configure_logging from twisted.internet import reactor from scrapy.settings import Settings import crawler_settings # 你的Scrapy配置模块 class Command(BaseCommand): help = 'Crawl for new data' def handle(self, *args, **options): configure_logging() settings = Settings() settings.setmodule(crawler_settings) runner = CrawlerRunner(settings) # 替换成你的Spider类 deferred = runner.crawl(YourSpiderClass) # 爬虫结束后手动停止Reactor deferred.addBoth(lambda _: reactor.stop()) reactor.run()
⚠️ 提醒:这种方式如果在同一个Celery worker进程中多次调用,还是可能触发Reactor错误,所以更推荐前面的多进程方案。
二、解决数据库SSL错误
这个错误基本是Django数据库配置和数据库服务器的SSL要求不匹配导致的,分两种场景处理:
场景1:生产环境数据库要求SSL连接
根据你用的数据库类型,修改settings.py中的DATABASES配置,添加SSL相关参数:
PostgreSQL示例:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'your_db_name', 'USER': 'your_db_user', 'PASSWORD': 'your_db_password', 'HOST': 'your_db_host', 'PORT': '5432', 'OPTIONS': { # 按数据库要求选sslmode:require/verify-ca/verify-full 'sslmode': 'require', # 如果需要验证证书,替换成你的证书路径 # 'sslrootcert': '/etc/ssl/certs/ca-certificates.crt', # 'sslcert': '/path/to/client-cert.pem', # 'sslkey': '/path/to/client-key.pem', }, } }
MySQL示例:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'your_db_name', 'USER': 'your_db_user', 'PASSWORD': 'your_db_password', 'HOST': 'your_db_host', 'PORT': '3306', 'OPTIONS': { 'ssl': { 'ca': '/path/to/ca.pem', 'cert': '/path/to/client-cert.pem', 'key': '/path/to/client-key.pem' } }, } }
场景2:本地开发环境无需SSL
如果是本地测试用的数据库(比如Docker里的实例)没开SSL要求,直接去掉SSL相关配置,或者明确禁用:
# PostgreSQL禁用SSL 'OPTIONS': {'sslmode': 'disable'}
最后验证
- 启动Celery worker:
celery -A your_project_name worker --loglevel=info - 在Django shell中调用
scheduled_crawl_task.delay()触发测试任务 - 查看日志,确认爬虫正常运行且数据成功存入数据库
内容的提问来源于stack exchange,提问作者Levi Moreira
相关产品推荐
相关产品推荐

