Solid Queue 是一个基于数据库的 Active Job 队列后端,在设计时考虑到了简单性和性能。
除了常规作业排队和处理之外,Solid Queue 还支持延迟作业、并发控制、重复作业、暂停队列、每个作业的数字优先级、按队列顺序排列的优先级以及批量排队(活动作业的perform_all_later
的enqueue_all
)。
Solid Queue 可与 MySQL、PostgreSQL 或 SQLite 等 SQL 数据库一起使用,并且它利用FOR UPDATE SKIP LOCKED
子句(如果可用)来避免在轮询作业时阻塞和等待锁。它依赖于 Active Job 进行重试、丢弃、错误处理、序列化或延迟,并且与 Ruby on Rails 的多线程兼容。
Solid Queue 在新的 Rails 8 应用程序中默认配置。但如果您运行的是早期版本,则可以按照以下步骤手动添加:
bundle add solid_queue
bin/rails solid_queue:install
这会将 Solid Queue 配置为生产活动作业后端,创建配置文件config/queue.yml
和config/recurring.yml
,并创建db/queue_schema.rb
。它还将创建一个bin/jobs
可执行包装器,您可以使用它来启动 Solid Queue。
完成此操作后,您必须在config/database.yml
中添加队列数据库的配置。如果您使用 SQLite,它将如下所示:
production :
primary :
<< : *default
database : storage/production.sqlite3
queue :
<< : *default
database : storage/production_queue.sqlite3
migrations_paths : db/queue_migrate
...或者如果您使用 MySQL/PostgreSQL/Trilogy:
production :
primary : &primary_production
<< : *default
database : app_production
username : app
password : <%= ENV["APP_DATABASE_PASSWORD"] %>
queue :
<< : *primary_production
database : app_production_queue
migrations_paths : db/queue_migrate
注意:调用bin/rails solid_queue:install
会自动添加config.solid_queue.connects_to = { database: { writing: :queue } }
到config/environments/production.rb
,因此不需要额外的配置(尽管你必须确保您使用database.yml
中的queue
名称来匹配!)。但是,如果您想在不同的环境(例如登台甚至开发)中使用 Solid Queue,则必须手动将该config.solid_queue.connects_to
行添加到相应的环境文件中。并且,与往常一样,确保您在config/database.yml
中使用的数据库名称与您在config.solid_queue.connects_to
中使用的名称匹配。
然后在生产中运行db:prepare
以确保创建数据库并加载架构。
现在您已准备好通过在正在执行工作的服务器上运行bin/jobs
来开始处理作业。这将开始使用默认配置处理所有队列中的作业。请参阅下文了解有关配置 Solid Queue 的更多信息。
对于小型项目,您可以在与网络服务器相同的计算机上运行 Solid Queue。当您准备好扩展时,Solid Queue 支持开箱即用的水平扩展。您可以在与 Web 服务器不同的服务器上运行 Solid Queue,甚至可以同时在多台计算机上运行bin/jobs
。根据配置,您可以指定某些机器仅运行调度程序或仅运行工作人员。有关详细信息,请参阅配置部分。
注意:未来对架构的更改将以定期迁移的形式出现。
建议在单独的数据库中运行 Solid Queue,但也可以为应用程序和队列使用一个数据库。只需按照以下步骤操作:
db/queue_schema.rb
的内容复制到普通迁移中,并删除db/queue_schema.rb
production.rb
中删除config.solid_queue.connects_to
bin/jobs
您不会有多个数据库,因此database.yml
不需要有主数据库和队列数据库。
如果您计划通过一次切换一项作业来逐步采用 Solid Queue,则可以将config.active_job.queue_adapter
设置保留为旧后端,然后直接在要移动的作业中设置queue_adapter
:
# app/jobs/my_job.rb
class MyJob < ApplicationJob
self . queue_adapter = :solid_queue
# ...
end
Solid Queue 旨在与 MySQL 8+ 或 PostgreSQL 9.5+ 一起使用时实现最高吞吐量,因为它们支持FOR UPDATE SKIP LOCKED
。您可以将其与旧版本一起使用,但在这种情况下,如果为同一队列运行多个工作线程,则可能会遇到锁等待。您还可以在较小的应用程序上将其与 SQLite 一起使用。
Solid Queue 中有几种类型的参与者:
solid_queue_ready_executions
表。solid_queue_scheduled_executions
表移动到solid_queue_ready_executions
表,以便工作人员可以拾取它们。最重要的是,他们做一些与并发控制相关的维护工作。Solid Queue 的主管将为每个受监督的工作人员/调度程序/调度程序分叉一个单独的进程。
默认情况下,Solid Queue 将尝试在config/queue.yml
下查找您的配置,但您可以使用环境变量SOLID_QUEUE_CONFIG
或使用bin/jobs
的-c/--config_file
选项来设置不同的路径,如下所示:
bin/jobs -c config/calendar.yml
此配置如下所示:
production :
dispatchers :
- polling_interval : 1
batch_size : 500
concurrency_maintenance_interval : 300
workers :
- queues : " * "
threads : 3
polling_interval : 2
- queues : [ real_time, background ]
threads : 5
polling_interval : 0.1
processes : 3
一切都是可选的。如果未提供任何配置,Solid Queue 将使用默认设置运行一名调度程序和一名工作人员。如果您只想运行调度程序或工作人员,则只需在配置中单独包含该部分即可。例如,使用以下配置:
production :
dispatchers :
- polling_interval : 1
batch_size : 500
concurrency_maintenance_interval : 300
主管将运行 1 名调度员,没有工人。
以下是不同选项的概述:
polling_interval
:工作人员和调度程序在检查更多作业之前等待的时间间隔(以秒为单位)。对于调度员,该时间默认为1
秒;对于工作人员,该时间默认为0.1
秒。
batch_size
:调度程序将按此大小批量调度作业。默认值为 500。
concurrency_maintenance_interval
:调度程序在检查可以解除阻塞的阻塞作业之前等待的时间间隔(以秒为单位)。阅读有关并发控制的更多信息以了解有关此设置的更多信息。默认为600
秒。
queues
:工作人员将从中选择作业的队列列表。您可以使用*
来指示所有队列(这也是默认值,如果您省略它,您将得到的行为)。您可以提供单个队列或作为数组的队列列表。作业将从这些队列中按顺序轮询,因此,例如,使用[ real_time, background ]
,不会从background
获取任何作业,除非real_time
中没有更多作业等待。您还可以提供带有通配符的前缀来匹配以前缀开头的队列。例如:
staging :
workers :
- queues : staging*
threads : 3
polling_interval : 5
这将创建一个工作人员,从staging
开始的所有队列中获取作业。通配符*
只能单独使用或出现在队列名称的末尾;您不能指定队列名称,例如*_some_queue
。这些将被忽略。
最后,您可以将前缀与确切的名称组合起来,例如[ staging*, background ]
,并且与顺序有关的行为将与仅使用确切名称时相同。
请查看以下部分,了解队列顺序如何与优先级结合使用,以及为每个工作线程指定队列的方式可能会如何影响性能。
threads
:这是每个工作线程必须运行作业的线程池的最大大小。每个工作人员最多将从其队列中获取此数量的作业,并将它们发布到线程池中运行。默认情况下,这是3
。只有工人有此设置。
processes
:这是主管根据给定的设置分叉的工作进程的数量。默认情况下,这是1
,只是一个进程。如果您想要将多个 CPU 核心专用于一个或多个具有相同配置的队列,则此设置非常有用。只有工人有此设置。
concurrency_maintenance
:调度程序是否执行并发维护工作。默认情况下这是true
,如果您不使用任何并发控制并想要禁用它,或者如果您运行多个调度程序并希望其中一些调度程序只调度作业而不执行任何其他操作,那么它会很有用。
如上所述,如果您为工作人员指定队列列表,这些队列将按照给定的顺序进行轮询,例如对于列表real_time,background
,不会从background
获取任何作业,除非没有更多作业在等待real_time
。
Active Job 在排队作业时还支持正整数优先级。在Solid Queue中,值越小,优先级越高。默认值为0
。
当您在同一队列中运行具有不同重要性或紧急程度的作业时,这非常有用。在同一个队列中,作业将按优先级顺序选取,但在队列列表中,队列顺序优先,因此在前面的real_time,background
示例中, real_time
队列中的作业将先于background
作业选取队列,即使background
队列中的那些设置了更高的优先级(较小的值)。
我们建议不要将队列顺序与优先级混合,而是选择其中之一,因为这将使作业执行顺序对您来说更加简单。
为了保持轮询性能并确保始终使用覆盖索引,Solid Queue 仅执行两种类型的轮询查询:
-- No filtering by queue
SELECT job_id
FROM solid_queue_ready_executions
ORDER BY priority ASC , job_id ASC
LIMIT ?
FOR UPDATE SKIP LOCKED;
-- Filtering by a single queue
SELECT job_id
FROM solid_queue_ready_executions
WHERE queue_name = ?
ORDER BY priority ASC , job_id ASC
LIMIT ?
FOR UPDATE SKIP LOCKED;
当您指定时,使用第一个(不按队列过滤)
queues : *
并且没有任何队列暂停,因为我们要定位所有队列。
在其他情况下,我们需要有一个队列列表来按顺序进行过滤,因为我们一次只能按一个队列进行过滤,以确保我们使用索引进行排序。这意味着如果您将队列指定为:
queues : beta*
我们需要首先获取与该前缀匹配的所有现有队列的列表,查询如下所示:
SELECT DISTINCT (queue_name)
FROM solid_queue_ready_executions
WHERE queue_name LIKE ' beta% ' ;
由于一种称为“松散索引扫描”的技术,这种针对索引中最左侧列的DISTINCT
查询可以在 MySQL 中非常快速地执行。然而,PostgreSQL 和 SQLite 没有实现这种技术,这意味着如果您的solid_queue_ready_executions
表非常大,因为您的队列变得非常深,则该查询将会变慢。通常你的solid_queue_ready_executions
表会很小,但这种情况也有可能发生。
与使用前缀类似,如果您暂停了队列,也会发生同样的情况,因为我们需要使用如下查询来获取所有队列的列表
SELECT DISTINCT (queue_name)
FROM solid_queue_ready_executions
然后删除暂停的。一般来说,暂停应该是罕见的,在特殊情况下使用,并且时间很短。如果您不想再处理队列中的作业,最好的方法是将其从队列列表中删除。
总而言之,如果您想确保轮询的最佳性能,最好的方法是始终为它们指定确切的名称,并且不要暂停任何队列。
这样做:
queues : background, backend
而不是这个:
queues : back*
Solid Queue 中的工作线程使用线程池在多个线程中运行工作,可通过上面的threads
参数进行配置。除此之外,并行性可以通过一台机器上的多个进程(可通过不同的工作进程或上面的processes
参数进行配置)或通过水平扩展来实现。
主管负责管理这些流程,并响应以下信号:
TERM
、 INT
:开始优雅终止。主管将向其受监督进程发送TERM
信号,并且它将等待SolidQueue.shutdown_timeout
时间,直到它们完成。如果那时任何受监督的进程仍然存在,它将向它们发送QUIT
信号以指示它们必须退出。QUIT
:开始立即终止。监督者将向其监督的进程发送QUIT
信号,使它们立即退出。当收到QUIT
信号时,如果工作人员仍有正在进行的作业,则在取消注册进程时,这些作业将返回到队列。
如果进程在退出之前没有机会进行清理(例如,如果有人在某处拉动电缆),则执行中的作业可能仍由执行它们的进程占用。进程发送心跳,主管检查并修剪心跳过期的进程,这会将任何已声明的作业释放回其队列。您可以配置心跳频率和阈值以将进程视为死亡。请参阅下面的部分了解这一点。
您可以通过config/application.rb
或config/environments/production.rb
配置文件中的config.solid_queue.connects_to
选项配置 Solid Queue 使用的数据库。默认情况下,使用称为queue
单个数据库进行写入和读取,以匹配您在安装过程中设置的数据库配置。
此处可以使用适用于多个数据库的 Active Record 的所有选项。
在 Solid 队列中,您可以连接到主管生活中的两个不同点:
start
:在supervisor完成启动之后,在fork工人和调度程序之前。stop
:收到信号( TERM
、 INT
或QUIT
)后,在开始正常或立即关闭之前。并分为工人生活中的两个不同点:
worker_start
:在工作进程完成启动之后和开始轮询循环之前。worker_stop
:在收到信号( TERM
、 INT
或QUIT
)之后,在开始正常或立即关闭(即exit!
)之前。您可以使用以下带有块的方法来执行此操作:
SolidQueue . on_start
SolidQueue . on_stop
SolidQueue . on_worker_start
SolidQueue . on_worker_stop
例如:
SolidQueue . on_start { start_metrics_server }
SolidQueue . on_stop { stop_metrics_server }
可以多次调用这些函数来添加多个钩子,但需要在 Solid Queue 启动之前进行。初始化程序将是执行此操作的好地方。
注意:本节中的设置应在config/application.rb
或环境配置中设置,如下所示: config.solid_queue.silence_polling = true
您也可以设置几个控制 Solid Queue 工作方式的设置:
logger
:您希望 Solid Queue 使用的记录器。默认为应用程序记录器。
app_executor
:用于包装异步操作的Rails执行器,默认为app执行器
on_thread_error
:当 Solid Queue 线程中出现错误(将引发的异常作为参数)时要调用的自定义 lambda/Proc。默认为
-> ( exception ) { Rails . error . report ( exception , handled : false ) }
这不用于作业执行中引发的错误。作业中发生的错误由 Active Job 的retry_on
或discard_on
处理,最终将导致作业失败。这是针对 Solid Queue 本身发生的错误。
use_skip_locked
:执行锁定读取时是否使用FOR UPDATE SKIP LOCKED
。将来会自动检测到这一点,目前,如果您的数据库不支持它,您只需将其设置为false
即可。对于 MySQL,版本 < 8,对于 PostgreSQL,版本 < 9.5。如果您使用 SQLite,这不会产生任何影响,因为写入是连续的。
process_heartbeat_interval
:所有进程将遵循的心跳间隔 - 默认为 60 秒。
process_alive_threshold
:进程在最后一次心跳后被视为死亡的等待时间 - 默认为 5 分钟。
shutdown_timeout
:在向受监督TERM
发送QUIT
版本请求立即终止之前,监督程序将等待的时间,默认为 5 秒。
silence_polling
:是否静默轮询工作人员和调度程序时发出的 Active Record 日志 - 默认为true
。
supervisor_pidfile
:主管在启动时将创建的 pid 文件的路径,以防止在同一主机上运行多个主管,或者以防万一您想将其用于运行状况检查。默认情况下它nil
。
preserve_finished_jobs
:是否将已完成的作业保留在solid_queue_jobs
表中 - 默认为true
。
clear_finished_jobs_after
:保留已完成作业的时间段(如果preserve_finished_jobs
为 true),默认为 1 天。注意:目前,无法自动清理已完成的作业。您需要通过定期调用SolidQueue::Job.clear_finished_in_batches
来完成此操作,但这将在不久的将来自动发生。
default_concurrency_control_period
:用作并发控制中duration
参数默认值的值。默认为 3 分钟。
Solid Queue 将为作业排队时发生的任何 Active Record 错误引发SolidQueue::Job::EnqueueError
。不引发ActiveJob::EnqueueError
的原因是,此错误由 Active Job 处理,导致perform_later
返回false
并设置job.enqueue_error
,将作业生成一个需要传递给perform_later
块。这对于您自己的作业非常有效,但对于 Rails 或其他 gem 排队的作业(例如Turbo::Streams::BroadcastJob
或ActiveStorage::AnalyzeJob
来说,失败很难处理,因为您无法控制对perform_later
调用在那种情况下。
在重复任务的情况下,如果在排队与该任务相对应的作业时引发此类错误,它将被处理和记录,但不会冒泡。
Solid Queue 通过并发控制扩展了 Active Job,允许您限制可以同时运行的特定类型或具有特定参数的作业数量。当以这种方式限制时,作业将被阻止运行,并且它们将保持阻塞状态,直到另一个作业完成并取消阻止它们,或者在设置的到期时间(并发限制的持续时间)过去之后。工作永远不会被丢弃或丢失,只会被阻止。
class MyJob < ApplicationJob
limits_concurrency to : max_concurrent_executions , key : -> ( arg1 , arg2 , ** ) { ... } , duration : max_interval_to_guarantee_concurrency_limit , group : concurrency_group
# ...
key
是唯一必需的参数,它可以是符号、字符串或过程,用于接收作业参数作为参数,并用于标识需要限制在一起的作业。如果过程返回 Active Record 记录,则将根据其类名和id
构建键。to
默认为1
。duration
默认设置为SolidQueue.default_concurrency_control_period
,其本身默认为3 minutes
,但您也可以配置。group
用于控制不同作业类的并发性。它默认为作业类名称。当作业包含这些控制时,我们将确保最多会同时执行产生相同key
的作业数量(表示to
),并且这种保证将持续每个排队作业的duration
。请注意,不能保证执行顺序,只能保证同时执行的作业(重叠)。
并发限制在排队时使用信号量的概念,工作原理如下:当作业排队时,我们检查它是否指定了并发控制。如果是,我们检查信号量中计算出的并发键。如果信号量打开,我们声明它并将作业设置为准备就绪。就绪意味着工作人员可以拿起它来执行。当作业完成执行时(无论成功还是不成功,导致执行失败),我们都会向信号量发出信号,并尝试使用相同的密钥(如果有)解锁下一个作业。解除下一个作业的阻塞并不意味着立即运行该作业,而是将其从阻塞状态转移到就绪状态。由于可能发生某些情况,阻止第一个作业释放信号量并解锁下一个作业(例如,有人拔掉工作线程运行的机器的插头),因此我们将duration
作为故障保护。被阻止超过持续时间的作业是要被释放的候选作业,但只有并发规则允许的数量,因为每个作业都需要经过信号量舞蹈检查。这意味着duration
实际上与排队或正在运行的作业无关,而是与阻塞等待的作业有关。
例如:
class DeliverAnnouncementToContactJob < ApplicationJob
limits_concurrency to : 2 , key : -> ( contact ) { contact . account } , duration : 5 . minutes
def perform ( contact )
# ...
其中contact
和account
是ActiveRecord
记录。在这种情况下,我们将确保同一帐户最多同时运行两个DeliverAnnouncementToContact
类型的作业。如果出于任何原因,其中一个作业花费的时间超过 5 分钟,或者在获取并发锁后 5 分钟内没有释放并发锁(向信号量发出信号),则具有相同密钥的新作业可能会获得该锁。
让我们看另一个使用group
例子:
class Box :: MovePostingsByContactToDesignatedBoxJob < ApplicationJob
limits_concurrency key : -> ( contact ) { contact } , duration : 15 . minutes , group : "ContactActions"
def perform ( contact )
# ...
class Bundle :: RebundlePostingsJob < ApplicationJob
limits_concurrency key : -> ( bundle ) { bundle . contact } , duration : 15 . minutes , group : "ContactActions"
def perform ( bundle )
# ...
在这种情况下,如果我们有一个Box::MovePostingsByContactToDesignatedBoxJob
作业为 id 为123
联系人记录排队,并且另一个Bundle::RebundlePostingsJob
作业同时为引用联系人123
捆绑记录排队,则只允许其中一个继续进行。另一个将保持阻塞状态,直到第一个完成(或 15 分钟过去,无论先发生什么)。
请注意, duration
设置间接取决于您为调度程序设置的concurrency_maintenance_interval
值,因为这将是检查和解除阻止的阻塞作业的频率。一般来说,您应该以一种方式设置duration
,以便所有作业都能在该持续时间内顺利完成,并将并发维护任务视为万一出现问题的故障保护。
作业按优先级顺序解除阻塞,但解除阻塞作业时不考虑队列顺序。这意味着,如果您有一组共享并发组但位于不同队列中的作业,或者您在不同队列中排队的同一类作业,则在解除阻塞时不会考虑您为工作线程设置的队列顺序那些。原因是,运行的作业会解锁下一个作业,并且作业本身不知道特定工作线程的队列顺序(甚至可以让不同的工作线程具有不同的队列顺序),它只能知道优先级。一旦被阻止的作业被解除阻止并可供轮询,它们将被工作人员按照其队列顺序拾取。
最后,自动或手动重试的失败作业的工作方式与排队的新作业相同:它们进入队列以获取打开的信号量,并且每当它们获取信号量时,它们就会运行。他们过去是否已经获得了开放的信号量并不重要。
Solid Queue 不包含任何自动重试机制,它依赖于 Active Job 来实现此目的。失败的作业将保留在系统中,并为其创建失败的执行( solid_queue_failed_executions
表中的一条记录)。该作业将保留在那里,直到手动丢弃或重新排队。您可以在控制台中执行此操作,如下所示:
failed_execution = SolidQueue :: FailedExecution . find ( ... ) # Find the failed execution related to your job
failed_execution . error # inspect the error
failed_execution . retry # This will re-enqueue the job as if it was enqueued for the first time
failed_execution . discard # This will delete the job from the system
但是,我们建议您查看mission_control-jobs,这是一个仪表板,您可以在其中检查并重试/放弃失败的作业。
一些与 Rails 集成的错误跟踪服务(例如 Sentry 或 Rollbar)会挂钩到 Active Job 并自动报告作业执行期间发生的未处理错误。但是,如果您的错误跟踪系统没有,或者您需要一些自定义报告,您可以自己连接到 Active Job。一种可能的方法是:
# application_job.rb
class ApplicationJob < ActiveJob :: Base
rescue_from ( Exception ) do | exception |
Rails . error . report ( exception )
raise exception
end
end
请注意,您还必须在ActionMailer::MailDeliveryJob
上复制上述逻辑。这是因为ActionMailer
不继承自ApplicationJob
,而是使用继承自ActiveJob::Base
ActionMailer::MailDeliveryJob
。
# application_mailer.rb
class ApplicationMailer < ActionMailer :: Base
ActionMailer :: MailDeliveryJob . rescue_from ( Exception ) do | exception |
Rails . error . report ( exception )
raise exception
end
end
如果您想将 Solid Queue 的管理程序与 Puma 一起运行并让 Puma 进行监控和管理,我们提供了一个 Puma 插件。你只需要添加
plugin :solid_queue
到你的puma.rb
配置。
因为这可能非常棘手,而且很多人不需要担心它,所以默认情况下,Solid Queue 配置在与主应用程序不同的数据库中,由于 Active Job 的内置功能,作业排队会被推迟,直到提交任何正在进行的事务为止。有能力做到这一点。这意味着即使您在与应用程序相同的数据库中运行 Solid Queue,您也无法利用这种事务完整性。
如果您想更改此设置,可以将config.active_job.enqueue_after_transaction_commit
设置为never
。您还可以根据每个作业进行设置。
如果您将其设置为never
但仍想确保不会无意中影响事务完整性,则可以确保:
依赖于特定数据的作业始终在after_commit
回调上排队,或者从您确定作业将使用的任何数据在作业排队之前已提交到数据库的位置排队。
或者,您为 Solid Queue 配置不同的数据库,即使它与您的应用程序相同,也确保处理请求或运行应用程序作业的线程上的不同连接将用于对作业进行排队。例如:
class ApplicationRecord < ActiveRecord :: Base
self . abstract_class = true
connects_to database : { writing : :primary , reading : :replica }
config . solid_queue . connects_to = { database : { writing : :primary , reading : :replica } }
Solid Queue 支持定义在未来特定时间运行的重复任务,就像 cron 作业一样定期运行。它们由调度程序进程管理,并在它们自己的配置文件中定义。默认情况下,该文件位于config/recurring.yml
中,但您可以使用环境变量SOLID_QUEUE_RECURRING_SCHEDULE
或使用bin/jobs
的--recurring_schedule_file
选项来设置不同的路径,如下所示:
bin/jobs --recurring_schedule_file=config/schedule.yml
配置本身如下所示:
production :
a_periodic_job :
class : MyJob
args : [ 42, { status: "custom_status" } ]
schedule : every second
a_cleanup_task :
command : " DeletedStuff.clear_all "
schedule : every day at 9am
任务被指定为哈希/字典,其中键将是任务内部的键。每个任务都需要有一个class
,它将是要排队的作业类,或者一个command
,它将在作业 ( SolidQueue::RecurringJob
) 的上下文中进行评估,该作业将根据其计划进行排队,在solid_queue_recurring
队列。
每个任务还需要有一个时间表,该时间表使用 Fugit 进行解析,因此它接受 Fugit 作为 cron 接受的任何内容。您可以选择为每个任务提供以下信息:
args
:要传递给作业的参数,作为单个参数、散列或参数数组,也可以包含 kwargs 作为数组中的最后一个元素。上面示例配置中的作业每秒都会排队如下:
MyJob . perform_later ( 42 , status : "custom_status" )
queue
:将作业排队时使用的不同队列。如果没有,则为作业类设置队列。
priority
:将作业排队时使用的数字优先级值。
任务由调度程序在相应的时间排队,每个任务都会调度下一个任务。这很大程度上受到 GoodJob 所做工作的启发。
可以使用相同的recurring_tasks
配置运行多个调度程序,例如,如果您有多个服务器用于冗余,并且在其中多个服务器中运行scheduler
。为了避免同时将重复任务排队,会在作业排队时在同一事务中创建新的solid_queue_recurring_executions
表中的条目。该表在task_key
和run_at
上有唯一索引,确保每次每个任务仅创建一个条目。仅当您将preserve_finished_jobs
设置为true
(默认值)时,这才有效,并且只要您保留作业,保证就适用。
注意:支持单个循环计划,因此您可以让多个计划程序使用相同的计划,但不能让多个计划程序使用不同的配置。
最后,可以配置 Solid Queue 不处理的作业。也就是说,您可以在您的应用程序中进行这样的工作:
class MyResqueJob < ApplicationJob
self . queue_adapter = :resque
def perform ( arg )
# ..
end
end
您仍然可以在 Solid Queue 中进行配置:
my_periodic_resque_job :
class : MyResqueJob
args : 22
schedule : " */5 * * * * "
并且该作业将通过perform_later
入队,因此它将在 Resque 中运行。但是,在这种情况下,我们不会跟踪它的任何solid_queue_recurring_execution
记录,并且不能保证该作业每次仅入队一次。
Solid Queue 的灵感来自于 resque 和 GoodJob。我们建议您查看这些项目,因为它们是很好的例子,我们从中学到了很多东西。
该 gem 根据 MIT 许可证条款作为开源提供。