Rails 7中ApplicationJob子类调用perform_later报未定义方法错误
问题背景
当前运行环境为Rails 7.0.3,创建了继承自ApplicationJob的简单任务类SimpleFileWriteTestJob,存放路径为app/jobs/simple_file_write_test_job.rb,代码如下:
class SimpleFileWriteTestJob < ApplicationJob queue_as :default def perform(*args) f = File.open("/tmp/project_job_test.txt", "a") f.puts("#{self.job_id}: #{DateTime.now}") f.close end end
在Rails控制台测试时,实例化该任务类后调用perform方法可正常运行,执行后/tmp/project_job_test.txt文件中成功写入了包含job_id和执行时间的内容,对应控制台执行记录如下:
irb(main):003:0> reload!; j = SimpleFileWriteTestJob.new; j.perform() Reloading... => nil
文件写入内容如下:
/opt/project-web # tail -f /tmp/project_job_test.txt e82cf2d1-f480-4bdc-bef2-975b084fe68d: 2022-07-12T19:10:53+00:00
但实例化后调用perform_later方法时触发NoMethodError,错误提示为undefined method 'perform_later',控制台报错记录如下:
irb(main):004:0> reload!; j = SimpleFileWriteTestJob.new; j.perform_later() Reloading... (irb):4:in `<main>': undefined method 'perform_later' for #<SimpleFileWriteTestJob:0x00007f6b007f0f90 @arguments=[], @job_id="07a747ad-fef7-4d28-8bd5-66ac7e31e2ac", @queue_name="default", @priority=nil, @executions=0, @exception_executions={}, @timezone="UTC"> (NoMethodError) reload!; j = SimpleFileWriteTestJob.new; j.perform_later() ^^^^^^^^^^^^^^ Did you mean? perform
已知active-job从Rails 4.2版本开始就已内置,无需在Gemfile中额外引入,需要确认该问题是否是因为没有安装队列后端导致perform_later无法使用,还是存在其他容易忽略的基础配置问题。
问题原因
该报错和队列后端无关,是调用方式错误:
perform是任务实例方法,手动new出任务实例后可直接调用,会同步执行任务逻辑perform_later是类方法,不属于任务实例,因此在实例对象上调用会触发找不到方法的错误
解决方案
不需要额外安装队列后端,Rails 7默认内置:async队列后端,开发环境可直接使用,只需要调整调用方式,不需要提前实例化任务对象,直接在任务类上调用perform_later即可:
# 错误写法 reload!; j = SimpleFileWriteTestJob.new; j.perform_later() # 正确写法 reload!; SimpleFileWriteTestJob.perform_later()
补充说明:
- 默认的
:async后端是内存级实现,Rails服务重启后未执行的任务会全部丢失,仅适合开发环境使用 - 生产环境需要根据业务需求配置Sidekiq、Resque、Delayed Job等持久化队列后端,保证任务不会丢失
内容的提问来源于stack exchange,提问作者Julien Lamarche
相关产品推荐
相关产品推荐

