2013-03-04 82 views
0

我使用DelayedJob处理后台中的某些任务。DelayedJob工作人员救援“RecordNotFound”错误

例如,在我的应用程序中,用户可以“喜欢”一条消息,当发生这种情况时,通知海报。此通知在后台处理。

偶尔,可能发生的事情是,liker决定撤消他的行为,并在通知发出之前删除他的“like”。在这些情况下,由于“like”不再存在,后台代码会遇到“RecordNotFound”错误。

我想我被抢救误差所以处理这种情况下(这里自我是等):

def send_push_notifications 
    begin 
     user = self.message.user 
     message = "#{self.user.name} liked your workout" 
     Urbanairship::push_now(user, message, ["message", self.message.id]) if self.user != user 
    rescue ActiveRecord::RecordNotFound 
     # Do nothing 
    end 
    end 

然而,在实践中,这似乎并没有被抢救的错误,我仍然看到这样的在我的日志中的错误:

{ActiveRecord::RecordNotFound, class: Like , primary key: 1557 
/app/vendor/bundle/ruby/1.9.1/gems/delayed_job-3.0.2/lib/delayed/serialization/active_record.rb:12:in `rescue in yaml_new' 
/app/vendor/bundle/ruby/1.9.1/gems/delayed_job-3.0.2/lib/delayed/serialization/active_record.rb:6:in `yaml_new' 
/usr/local/lib/ruby/1.9.1/syck.rb:135:in `transfer' 
/usr/local/lib/ruby/1.9.1/syck.rb:135:in `node_import' 
/usr/local/lib/ruby/1.9.1/syck.rb:135:in `load' 
/usr/local/lib/ruby/1.9.1/syck.rb:135:in `load' 

任何想法为什么我的救援声明不起作用在这种情况下?

+0

在Urbanairship :: push_now呼叫之前它失败吗?你能粘贴整个堆栈跟踪吗? – 2013-03-04 22:13:16

+0

对不起,这里是完整的堆栈跟踪:https://gist.github.com/pejmanjohn/8cf9f1f1d55a90f1ae39 – pejmanjohn 2013-03-04 22:20:40

+0

你确定你的'begin'和'rescue'之间发生错误吗?尝试在'begin'之后直接添加'raise ActiveRecord :: RecordNotFound'。如果这种方法有效并且被捕获,那么将它直接移到“抢救”之前并尝试。也许这可以给你一些线索...... – 244an 2013-03-05 01:04:07

回答

0

我终于用一个类的方法,而不是我的延迟调用一个实例方法解决了这个。让我以示例的方式展示给你。以下是我以前的结构我的延时电话:

def background_send_push_notifications 
    self.delay.send_push_notifications 
    end 

    def send_push_notifications 
    message = "#{self.user.name} liked your workout" 
    ... 
    end 

我不停地打的问题是,这是常见的用户立刻不同,喜欢的东西之后。这意味着,当delayed_job尝试执行时,Like对象不再存在,并且会出现很多“RecordNotFound”错误。

现在我已经将延迟调用转换为在后台执行对象查找的类方法,并在其不再存在时返回。这里的新结构

def background_send_push_notifications 
    Like.delay.send_push_notifications(self.id) 
    end 

    def self.send_push_notifications(id) 
    like = Like.find_by_id(id) 
    like.send_push_notifications unless like.nil? 
    end 

    def send_push_notifications 
    message = "#{self.user.name} liked your workout" 
    ... 
    end 

希望这可以帮助别人!

1

Like对象不存在,所以救援方法甚至没有被调用。

尝试将您的延迟方法定义为类方法,而不是实例方法。这样,即使实例不存在,延迟作业也能够执行该方法。例如,

class Like < ActiveRecord::Base 

... 

def self.send_push_notifications(like_id=nil) 
    begin 
    like = Like.find like_id 
    user = like.message.user 
    message = "#{like.user.name} liked your workout" 
    Urbanairship::push_now(user, message, ["message", like.message.id]) if like.user != user 
    rescue ActiveRecord::RecordNotFound 
    # Do nothing 
    end 
end 

... 

end 
+0

不,那不是那么正确。 Delayed_job会重试失败的作业。它保持一个计数,并重新尝试n次,其中n是可配置的(默认是25我相信)。失败次数越多,再次重试之前等待的时间越长。 DelayedJob.retry_at属性是下一次尝试的时间。现在仔细看,我认为你的救援不会被调用,因为Like对象不存在。将send_push_notifications重新定义为类方法,而不是实例方法,则即使对象不存在,delayed_job也可以调用它。如果您需要更多解释,我会编辑答案。 – pduey 2013-04-19 13:44:22

+0

更多的澄清,将不胜感激。我可以告诉你,我正在检查重试属性,它在这些作业上是“0”,而在其他失败的作业中,我确实看到多次退役。 – pejmanjohn 2013-04-19 17:15:54