如何用Python构建一个分布式任务队列

378 阅读3分钟

为什么不直接使用Celery/RQ/Huey/TaskTiger?

不幸的是,WakaTime使用Celery已经快10年了。在这段时间里,我经历了许多关键的Bug,有些在推出多年后仍未解决。Celery曾经很不错,但功能的膨胀使得这个项目难以维护。另外在我看来,将代码分割成三个独立的GitHub仓库使得代码库难以阅读:

然而,最主要的原因是,Celery的延迟任务没有规模。

如果你使用Celery延迟任务,随着网站的增长,最终你会开始看到这个错误信息

QoS: Disabled: prefetch_count exceeds 65535

当这种情况发生时,工作者就会停止处理所有的任务,而不仅仅是延迟的任务!随着WakaTime的发展,我们开始更频繁地遇到这个错误。

我试过RQHueyTaskTiger,但它们都缺少功能,而且处理任务的速度比Celery慢。对于像WakaTime这样的网站来说,分布式任务队列是不可或缺的,而且我已经厌倦了遇到bug的日子。出于这个原因,我决定建立一个最简单的分布式任务队列,同时仍然提供WakaTime所需的所有功能。

介绍一下WakaQ

WakaQ是一个新的Python分布式任务队列。用它来在后台运行代码,这样你的网站就会保持快速和敏捷,你的用户也会保持快乐。

WakaQ很简单

它只有1264行代码!

$ find . -name '*.py' -not -path "./migrations*" -not -path "./venv*" | xargs wc -l | grep " total" | awk '{print $1}' | numfmt --grouping
1,264

从第一行代码到完全取代WakaTime的Celery只用了一周时间。这说明了它的简单性。

每个队列都是用Redis列表实现的。延迟任务有自己的队列,使用Redis排序的集合实现。广播任务共享一个Redis Pub/Sub队列

WakaQ拥有所有必要的功能

  • 队列优先级
  • 延迟任务(在某个时间点后运行任务)。
  • 预定的cron定期任务
  • 广播任务(在所有工作者上运行一个任务)
  • 任务超时和超时限制
  • 在软超时时可选择重试任务
  • 当达到max_mem_percent时,通过重新启动worker来防止内存泄漏。
  • 超级简约和可维护

被认为超出范围的功能是速率限制、独占锁、存储任务结果和任务链。这些都很容易在你的应用程序的任务代码中添加,而且你可能想根据你的应用程序的需要来实现这些特定的功能。

WakaQ已经可以使用了

WakaQ仍然是一个新的项目,所以使用时要自己承担风险。WakaQ目前为WakaTime网站的prod中的所有后台任务提供动力,包括但不限于:

  • 发送代码统计的电子邮件报告
  • 更新我们的LetsEncrypt SSL证书
  • 预先缓存仪表盘、回购徽章和可嵌入的图表
  • 其他我们不希望耽误网络请求的东西。

它是在BSD许可下发布的,所以你可以在开放和闭源项目中使用它。如果你发现任何bug,请打开一个问题,但在要求新功能之前请三思而后行 :-)

编码愉快!