Delayed_job无法执行perform方法,但会清空作业队列。

17

我有一个全新的Rails 3应用程序,以下是我的Gemfile:

source 'http://rubygems.org'
gem 'rails', '3.0.0' gem 'delayed_job'
gem 'sqlite3-ruby', :require => 'sqlite3'

这是代表我想排队的工作的类:

class Me < Struct.new(:something)
   def perform
     puts "Hello from me"
     logger.info "Hello from me"
     logger.debug "Hello from me"
     raise Exception.new   
   end
end

从没有运行任何工作程序的控制台:

irb(main):002:0> Delayed::Job.enqueue Me.new(1)
=> #<Delayed::Backend::ActiveRecord::Job id: 7, priority: 0, attempts: 0, handler: "--- !ruby/struct:Me \nsomething: 1\n", last_error: nil, run_at: "2010-12-29 07:24:11", locked_at: nil, failed_at: nil, locked_by: nil, created_at: "2010-12-29 07:24:11", updated_at: "2010-12-29 07:24:11">

就像我之前提到的:当前没有运行的工作进程:

irb(main):003:0> Delayed::Job.all
=> [#<Delayed::Backend::ActiveRecord::Job id: 7, priority: 0, attempts: 0, handler: "--- !ruby/struct:Me \nsomething: 1\n", last_error: nil, run_at: "2010-12-29 07:24:11", locked_at: nil, failed_at: nil, locked_by: nil, created_at: "2010-12-29 07:24:11", updated_at: "2010-12-29 07:24:11">]

我使用script/delayed_job run启动一个工作进程。

队列被清空:

irb(main):006:0> Delayed::Job.all
=> []

然而,由于puts没有产生任何结果,logger也没有记录任何内容,也没有引发任何异常。 我会非常感激任何帮助/见解或任何可以尝试的方法。


我有完全相同的问题。你解决了吗? - Leddo
6个回答

12

默认情况下,delayed_job 会销毁失败的任务:

因此第一步是配置一个初始化程序并停用该行为。

Delayed::Worker.destroy_failed_jobs = false  

此外,如果发生反序列化失败,那么作业将立即失败。

这会触发作业删除(如果您尚未删除该作业)。

因此,请尝试在 worker.rb 文件的第 120 行左右添加以下内容:

rescue DeserializationError => error
  say "DeserializationError: #{error.message}"
  job.last_error = "{#{error.message}\n#{error.backtrace.join('\n')}"
  failed(job)

这并没有太多帮助,但至少你会知道这是一个反序列化错误。

最终我只使用了job w. perform()方法结构。更加可靠。另外记得将作业定义放在一个单独的文件中,以便类加载器可以在运行时找到它(而不仅是将类定义内联到你的模型中的某个位置)。


6
本W是完全正确的,确保你在文件下有一个
"#{Rails.root}/config/initializers/delayed_job_worker.rb"

这定义了工作者的行为方式。如果有错误,工作者会悄悄地将其删除。
一旦这样做,您就可以更多地了解您的错误。对于我的例子,我正在使用delayed_job_mongoid,所以这增加了一个"last_error"的条目(不管怎样,我认为您应该在mysql表中为延迟作业添加此条目..)。
正如Ben W所得出的结论,您需要确保您创建的对象已知于应用程序(或对于工作者而言)。 我的问题是我在Rails Console中测试一个类对象。工作者不知道这个类,所以它失败了。
在我的application.rb文件中:
module TextSender
  class Application < Rails::Application
    require "#{Rails.root.to_s}/lib/SendTextJob.rb"

我的库文件:

class SendTextJob < Struct.new(:text, :number)
  def perform
    Rails.logger.info "Sending #{text} to #{number}"
    puts "Successfully sent text"
  end
end

然后运行。
Delayed::Job.enqueue SendTextJob.new("Work on this text NOW, please?", "5551231234")

已在我的日志/development.log文件中确认此操作成功。我还在此perform方法中测试了创建对象(用户对象或您可能拥有的其他模型),并且它也成功了。


3

我曾经也遇到过这个问题,后来发现是因为在Rails 3中,lib/目录下的文件没有被自动加载。为了进行诊断,我添加了以下代码:

# application.rb
Delayed::Worker.destroy_failed_jobs = false

正如Ben W.所提到的,他告诉我发生了什么事情,因为我可以检查last_error

为了解决自动加载问题,我在SO上找到了几个答案,但要点是添加这个:

# application.rb

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

这篇文章很友好地提供了一个链接:http://hemju.com/2010/09/22/rails-3-quicktip-autoload-lib-directory-including-all-subdirectories/

不开启 lib 目录的自动加载,你有什么想法吗?我很感兴趣,希望能看到你的解决方案。


0

我刚刚将你的类复制到irb中并尝试执行Me.new.perform

Hello from me
NameError: undefined local variable or method `logger' for #<struct Me something=nil>
from (irb):6:in `perform'
from (irb):14

你的类可以访问'logger'吗?
你可以尝试做其他事情,比如打开并写入文件?
File.open("testing.txt", 'w') {|f| f.write("hello") }

请注意,延迟作业工作者的“puts”命令将输出到它自己的stdout,因此您可能永远看不到这个输出。如果您想要进行任何日志记录,我认为您必须在perform方法中创建一个新的Logger实例才能这样做。

我尝试删除日志记录调用并按照您的描述编写文件。我仍然看到相同的行为 - 作业从队列中删除,但文件没有被写入。 - James

0

是的,我相信它是主分支,版本号为2.1。 - James

0

检查日志,你应该能看到有关DelayedJob消息的内容,至少可以知道哪个任务被启动以及其退出状态是什么

在终端中运行:

tail -f log/development.log

然后从Rails控制台重试,执行一个简单的ActiveRecord查询,然后使用DelayedJob。您可以阅读在另一个终端中记录的内容。

祝福, A.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接