GoodJob 1.0,一个新的基于Postgres的多线程ActiveJob Rails后端

2020-07-22 23:26:23

受Delayed::Job和Que的启发,GoodJob旨在最大限度地兼容Ruby on rails、ActiveJob和Postgres,使其对于大多数工作负载都是简单和高效的。

专为ActiveJob设计。使用几乎为零的配置完全支持异步、队列、延迟、优先级、超时和重试。

为Rails构建的。完全采用Ruby on rails的线程化和代码执行指南,并使用Concurrent::Ruby。

在波斯格雷斯的支持下。依赖Postgres完整性和会话级咨询锁来提供一次性运行安全性,并保持在schema.rb的限制内。

对于大多数工作负载。目标客户是全堆栈团队、有经济头脑的独立开发人员和每天入队作业不到100万个的应用程序。

有关将GoodJob添加到Rails应用程序的说明,请访问Github,或者继续阅读GoodJob背后的故事。

为什么是“第二代*”?GoodJob从一开始就被设计为传统Ruby on rails应用程序中的ActiveJob后端。

第一代ActiveJob后端,如Delayed::Job和Que,都早于ActiveJob并支持非Rails应用程序。第一代ActiveJob后端要比GoodJob复杂得多,因为它们分别维护了传统Rails安装(ActiveRecord、ActiveSupport、Concurrent:Ruby)附带的许多功能,并重新实现了作业生命周期挂钩,这样它们就可以脱离ActiveJob工作。我观察到,这会使他们跟不上Rails的重大更改。GoodJob的一个推动力是回顾了多年来我在主要和次要Rails升级期间管理的第一代后端的停机、受阻升级和分叉的数量。

作为第二代ActiveJob后端,GoodJob可以提炼出ActiveJob和Ruby on rails的所有进步和解决的问题。例如,REASURE_FROM、RETRY_ON、DISCARD_ON都已由ActiveJob实现。

GoodJob比第一代后端要薄得多,从长远来看,希望更容易维护和跟上Ruby on rails的变化。例如,GoodJob当前有大约600行代码,而QUE大约有1,200行,而Delayed::JOB大约有2,300行(2,000行用于DELAYED_JOB,另外300行用于DELAYED_JOB_ACTIVE_RECORD)。

*“第二代”是丹尼尔·洛佩兹(Daniel Lopez)在Ruby on Rails Link Slake上为我创造的。

我喜欢波斯格雷斯。Postgres提供了很多功能,有安全和完整性保证,而且简单地运行更少的服务(跳过Redis)就意味着开发和生产的复杂性更低。

GoodJob使用会话级咨询锁来提供一次性运行保证,并且对大多数工作负载的性能影响相对较小。

GoodJob的会话级咨询锁实现可能是唯一的“新颖”方面,这来自于我为Code for America编排复杂的政府系统网络驱动(“浏览器就是API”)的经验。GoodJob使用公用表表达式(CTE)在单个查询中查找、锁定和返回下一个可工作的作业。如果中断,会话级咨询锁将优雅地放弃该锁,而不必在作业期间维护事务。

GoodJob使用Concurrent::Ruby跨多个线程扩展和管理作业。“并发Ruby是所有Ruby并发性库中最强大的线程安全保证之一”。Ruby on rails采用了并发Ruby,GoodJob遵循其主导、线程执行和安全准则。

在构建GoodJob时,我很大程度上依赖于在Heroku上运行QUE(另一个多线程后端)的积极经验。对于典型的IO密集型工作负载(如繁重的数据库查询、API请求、Selenium Web驱动或发送电子邮件)而言,线程非常适合平衡简单性、经济性和性能。

GoodJob 1.0中不会有一个功能,但我希望很快就能实现,那就是在Web服务器进程内运行GoodJob调度程序的能力(“异步模式”)。这是QUE中取消的一个特性,但我相信使用并发Ruby可以安全地实现。异步模式将提供更大的经济性,例如,在Heroku的受限环境中。

GoodJob的设计直接基于我在两个披萨的全栈团队中的经验,以及作为一个节俭的单独开发人员。GoodJob已经为Day of the Shirt和Brompt提供了支持,它们每天处理数以万计的现实世界工作。