RQ更适合轻量场景,因其仅依赖Redis、配置极简(一条命令启动worker)、无须Broker选型与复杂监控;适合Django中异步发邮件、导出Excel等简单任务,避免Celery的高配置成本。

为什么选 RQ 而不是 Celery?
Django 项目如果只是需要异步发邮件、生成报表或清理缓存这类简单后台任务,Celery 的配置成本(Broker 选型、worker 进程管理、监控、序列化兼容性)很容易超过任务本身复杂度。RQ(Redis Queue)用 Redis 做底层队列,只依赖一个 redis 包,rq 本身不到 1000 行代码,启动一个 worker 就是一条命令:rq worker。它不支持定时任务、多 Broker、优先级队列等高级功能——这反而是轻量场景的优势:没得选,也就不用纠结。
适合场景包括:
- Django Admin 中点击“导出 Excel”后异步执行,返回任务 ID 页面轮询
- 用户注册后异步发欢迎邮件,不阻塞 HTTP 响应
- 定时脚本(用
django-cron或系统 crontab 触发)调用 RQ 推送一批任务
在 Django 中集成 RQ 的最小可行配置
核心是让 RQ worker 能 import 到你的 Django 模块,并共享 settings 和 ORM。不需要改 Django 启动逻辑,也不用写自定义 management command 来加载环境——直接用 manage.py 启动 worker 即可。
步骤如下:
- 安装:
pip install django-rq redis(django-rq是封装层,提供 admin 集成和配置简化) - 在
settings.py中添加:RQ_QUEUES = { 'default': { 'HOST': 'localhost', 'PORT': 6379, 'DB': 0, 'DEFAULT_TIMEOUT': 360, }, } - 在
INSTALLED_APPS加入'django_rq' - 运行
python manage.py rqworker启动 worker(它会自动识别RQ_QUEUES并加载 Django 环境)
注意:rqworker 命令来自 django-rq,不是原生 rq 的 rq worker;后者无法自动加载 Django settings,会导致 django.core.exceptions.AppRegistryNotReady。
如何从视图中安全地入队函数
RQ 只能序列化纯函数(不能是类方法、闭包、lambda),且函数必须能被字符串路径导入(即模块可 import)。Django 中最稳妥的方式是把任务函数放在 tasks.py 文件里,和 views 同级或放在 app 根目录。
例如,在 myapp/tasks.py 中写:
from django.core.mail import send_mail
<p>def send_welcome_email(user_id):</p><h1>注意:不要直接传 model 实例!</h1><pre class="brush:python;toolbar:false;">from myapp.models import User
user = User.objects.get(id=user_id)
send_mail('Welcome', f'Hi {user.username}', 'from@example.com', [user.email])
在 view 中调用:
from django_rq import get_queue
from myapp.tasks import send_welcome_email
<p>def register_view(request):</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill11526" title="Python Hardener"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20dbae7c507.jpg" alt="Python Hardener" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill11526" title="Python Hardener" class="overflowclass">Python Hardener</a>
<p class="overflowclass">通过完整的安全审查、代码整洁重构、健壮的错误处理、正确的日志记录以及完整的文档字符串覆盖,强化 Python 脚本。</p>
</div>
<a rel="nofollow" href="/xiazai/skill11526" title="Python Hardener" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h1>... 创建 user 后</h1><pre class="brush:python;toolbar:false;">queue = get_queue('default')
queue.enqueue(send_welcome_email, user.id) # 传参数,不是实例
return JsonResponse({'task_id': queue.last_job_id})
关键点:
- 绝对不要传
User()实例进enqueue()——pickle会失败,且跨进程时 ORM state 不一致 - 函数内部重新
importmodel,避免模块循环引用 -
get_queue()返回的是rq.Queue实例,不是 Django model,别和Queue模型名冲突
RQ + Django 的常见坑与绕过方式
RQ 默认用 pickle 序列化,而 Django 的 QuerySet、Model 实例、request 对象都不能被安全 pickle。这不是 bug,是设计限制。
典型报错:
-
TypeError: can't pickle _thread.RLock objects→ 说明你传了带线程锁的对象(比如未关闭的数据库连接或缓存 client) -
AttributeError: Can't get attribute 'MyView' on→ 函数不在可 import 路径下,比如写在 views.py 里又没加if __name__ == '__main__':保护 - worker 日志里出现
ModuleNotFoundError→manage.py rqworker启动时 Python path 没包含你的 app 目录(检查sys.path或用--path参数)
性能上,RQ 单 worker 是单线程,CPU 密集型任务会阻塞。若需并发,启动多个 worker:python manage.py rqworker --workers 4,每个 worker 独立进程,共享同一 Redis 队列。
Redis 本身不持久化任务(除非开启 AOF/RDB),任务失败后默认丢弃。如需重试,用 queue.enqueue(..., failure_ttl=600) 并配合 rq-dashboard 查看失败任务手动重入队。
RQ 不处理“任务去重”或“唯一队列”,需要自己在入队前查 Redis key 或加数据库锁——这点比 Celery 的 ignore_result=True + task_id 控制更原始,但也更透明。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










