dramatiq 比 celery 更适合 django 小型任务看板,因其启动快、依赖少、仅需队列服务(如 redis)、配置简单;celery 需 broker + result backend + 进程管理,配置复杂。

为什么 Dramatiq 比 Celery 更适合 Django 小型任务看板
Dramatiq 在轻量级异步任务场景下启动快、依赖少、不依赖 Redis 的 Pub/Sub(只用队列),对 Django 小项目更友好。Celery 默认要配 broker + result backend + worker 进程管理,而 Dramatiq 只需一个 redis 或 memcached 实例存队列,worker 启动命令也更直白。
常见错误现象:ConnectionRefusedError: [Errno 111] Connection refused —— 多数是没起 Redis,或 Django 的 DRAMATIQ_BROKER 配置写错 host/port;还有人误把 Dramatiq 当成 Celery 用,硬套 @shared_task 装饰器,结果函数根本没注册进 broker。
- 使用场景:用户提交表单后发邮件、生成报表 PDF、批量更新看板卡片状态等「耗时但不强实时」操作
- Django 中必须在
settings.py显式配置DRAMATIQ_BROKER,不能靠环境变量自动 fallback - 性能影响:Dramatiq 默认启用
MessagePack序列化,比 JSON 快且体积小;但如果任务参数含 datetime / Decimal 等非标准类型,得自己加encoder和decoder
怎么在 Django 里定义并触发一个看板卡片同步任务
任务函数必须放在 tasks.py(Dramatiq 会自动扫描该文件),且用 @actor 装饰——不是 @task,也不是 def task_* 这种命名约定。
示例:同步某张卡片到外部 API
from dramatiq import actor
from myapp.models import Card
<p>@actor
def sync_card_to_external(card_id):
try:
card = Card.objects.get(id=card_id)</p><h1>实际调用 requests.post(...)</h1><pre class="brush:python;toolbar:false;"> card.sync_status = "success"
except Card.DoesNotExist:
pass # 卡片已被删,不报错
except Exception as e:
card.sync_status = f"error: {e}"
finally:
card.save()
触发方式很简单,在视图或信号里调用 .send():
-
sync_card_to_external.send(card.id)—— 异步投递,立刻返回 -
sync_card_to_external.send_with_options(args=(card.id,), delay=5000)—— 延迟 5 秒执行 - 别直接调用
sync_card_to_external(card.id),那只是普通函数调用,不会进队列 - 参数只能是 JSON-serializable 类型(
int、str、dict、list),不能传Card实例本身
Django Admin 里怎么安全地重试失败的 Dramatiq 任务
Dramatiq 自带 Web UI(dramatiq-admin),但它不和 Django Admin 深度集成,也没提供「点一下重试」按钮。真要从 Admin 操作,得自己加个 admin action。
容易踩的坑:message.requeue() 不等于重试——它只是把原 message 再塞回队列,如果失败原因是数据库连接断开,重入队列后大概率再次失败;更稳妥的是用 message.copy().send() 生成新 message。
- 先在
admin.py注册一个 action,接收选中的任务 ID(来自自定义日志表或 Dramatiq 的Message表) - 从
dramatiq.broker.get_broker().get_queue("default").fetch_message(...)拿不到已消费消息,所以得自己建一张TaskLog模型记录失败任务的message_id、args、traceback - 重试逻辑里记得加
max_retries=2和指数退避,避免雪崩 - 不要在 Admin action 里直接调用
broker.enqueue(...),要用actor.send_with_options(...)保证序列化一致
本地开发时 Dramatiq worker 怎么热重载不重启
默认 dramatiq 启动后不会监听文件变化,改了 tasks.py 必须手动 Ctrl+C 再 dramatiq myproject。开发看板功能时频繁改任务逻辑,这很打断节奏。
解决方案是用 watchdog + subprocess 手写一个轻量 watcher,或者直接上 python -m dramatiq watch myproject(Dramatiq 1.12+ 支持)。
- 运行前确认
pip install watchdog已安装,否则watch子命令会报错ModuleNotFoundError: No module named 'watchdog' -
watch默认只监控tasks.py,如果任务分散在多个 app,得用--path myapp1/tasks.py myapp2/tasks.py - 它不会 reload Django 的 model 或 view,只 reload
@actor函数,所以改了Card.save()逻辑仍需重启 dev server - 别在生产环境用
watch,它会持续 fork 进程,内存泄漏风险高
复杂点在于:Dramatiq 的 actor 是模块级对象,reload 后旧 actor 实例还挂在 broker 里,新旧混用可能造成消息丢失。真要稳定,还是得接受「改完 tasks.py 就 Ctrl+C 一次」这个现实。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











