代码实验室 - 使用Postgres的任务队列

代码实验室 - 使用Postgres的任务队列

💡 原文英文,约1000词,阅读约需4分钟。
📝

内容提要

文章讨论了如何利用Postgres的SKIP LOCKED功能定期调度任务,以提醒Slack用户审查GitHub拉取请求。通过创建工作队列,工人可以在未来执行任务,并在失败时进行重试。使用Quart框架和自定义数据库事务装饰器简化代码,同时测试套件利用unittest.IsolatedAsyncioTestCase进行异步测试,确保数据库在每次测试后恢复到初始状态。

🔎

延伸解读

为什么选择Postgres而非专用队列

文章指出,使用Postgres的SKIP LOCKED可以避免引入第三方消息系统或维护队列库,从而减少资源消耗。作者认为,在技术行业趋于精简的背景下,这种利用现有数据库实现任务队列的方式更高效、成本更低,尤其适合常见规模的工作负载。

Quart框架的定位与现状

Quart是Flask的异步版本,两者同属Pallets项目,目前正在合并,未来将成为一个同时支持同步和异步的框架。尽管Python生态中已有FastAPI、Sanic等异步框架,Quart却较少被讨论,但熟悉Flask的开发者可以快速上手。

任务去重与重试机制

系统通过Postgres的MD5自动生成列,确保相同类型和参数的任务不会重复入队。任务失败时会以指数退避方式重试,直到达到Job.max_retries设定的最大次数。这种设计避免了重复任务,并提高了任务执行的可靠性。

测试策略与性能优化

测试套件使用unittest.IsolatedAsyncioTestCase,在asyncSetUp中启动事务,asyncTearDown中回滚,使数据库在每次测试后恢复初始状态。对于延迟任务,通过freezegun冻结时间模拟未来执行。这种设置避免了重复的数据库初始化,在大型测试套件中能显著提升速度。

❓

Q&A

如何使用Postgres的SKIP LOCKED功能来调度任务?

使用SKIP LOCKED功能可以确保单个工人原子性地从任务队列中提取任务,避免多个工人同时提取同一任务。

Quart框架在这个任务调度系统中有什么作用?

Quart框架是Flask的异步版本,简化了代码并支持异步任务处理。

如何确保任务在失败时能够重试?

任务失败后会进行重试,采用指数退避策略,最多重试Job.max_retries次。

测试套件是如何确保数据库状态的?

测试套件使用unittest.IsolatedAsyncioTestCase,确保每次测试后数据库恢复到初始状态。

如何创建一个新的任务?

创建任务时,可以设置任务类型和参数,并指定任务的执行时间,例如使用Job类来定义任务。

在这个系统中,如何处理任务的并发执行?

通过SKIP LOCKED和DELETE ... SELECT FOR UPDATE的组合,确保没有工人同时获取同一任务。

🏷️

标签

➡️

继续阅读