假设我在后台运行了delayed_job。任务可以安排或立即运行(有些是长期任务,有些则不是)
如果任务太长,用户应该可以取消它。延迟工作有可能吗?我检查了文档,似乎无法找到终止方法或其他东西。它们只提供一个捕获来取消延迟的作业本身(因此取消所有任务......我只需要取消某个正在运行的任务)
更新 我的老板(谁是一个伟大的程序员顺便说一句)建议使用Ruby Threading来实现我们的这个功能。这可能吗?就像为每个任务创建新线程并在线程运行时终止该线程一样?
类似的东西:
t1 = Thread.new(task.run)
self.delay.t1.join (?) -- still reading on threads so correct me if im wrong
然后停止它我将只使用t1.stop(?)再次不知道
这可能吗?谢谢!
答案 0 :(得分:3)
似乎我的老板到了现场,所以这就是我们所做的(请告诉我们是否有可能这是不好的做法,所以我可以提出来):
Time.now
是否> finished_at
。如果是这样,请杀死该线程。瞧!我们为一项工作测试了它,它似乎工作。现在唯一的问题是缩放......
如果你发现任何问题,请在评论中这样做或提出更多建议:)我希望这对一些人也有帮助!
答案 1 :(得分:2)
Delayed::Job
是< ActiveRecord::Base
模型,因此您可以像平常一样查询Delayed::Job.all(:conditions => {:last_error => nil})
。
Delayed :: Job对象有一个有效负载字段,其中包含您尝试运行的方法或作业的序列化版本。这个对象可以通过'#payload_object'方法访问,该方法加载有问题的对象。
您可以将这两个功能组合在一起,以创建可查询的工作工作人员,例如,如果您有User
模型,并且用户有一个回形针:avatar
,那么您可以创建一个方法像这样删除未经处理的作业:
class User < ActiveRecord::Base
has_attached_file :avatar, PaperclipOptions.new(:avatar)
before_create :'process_avatar_later'
def process_avatar_later
filename = Rails.root.join('tmp/avatars_for_processing/',self.id)
open(filename, 'w') do |file| file <<self.avatar.to_file end
Delayed::Job.enqueue(WorkAvatar.new(self.id, filename))
self.avatar = nil
end
def cancel_future_avatar_processing
WorkAvatar.future_jobs_for_user(self.id).each(&:destroy)
#ummm... tell them to reupload their avatar, I guess?
end
class WorkAvatar < Struct.new(:user_id, :path)
def user
@user ||= User.find(self.user_id)
end
def self.all_jobs
Delayed::Job.scoped(:conditions => 'payload like "%WorkAvatar%"')
end
def self.future_jobs_for_user(user_id)
all_jobs.scoped(:conditions => {:locked_at => nil}).select do |job|
job.payload_object.user_id == user_id
end
end
def perform
@user.avatar = File.open(path, 'rb')
@user.save()
end
end
end
有人可能会制作一个插件,使这样的可查询对象。也许在GitHub上搜索会很有成效。
另请注意,如果要取消具有locked_at
和{{1}的作业,则必须使用任何流程监视工具来取消正在执行的正在运行的作业工作进程。 } set。
答案 2 :(得分:1)
您可以将任务包装到Timeout
语句中。
require 'timeout'
class TaskWithTimeout < Struct.new(:parameter)
def perform
Timeout.timeout(10) do
# ...
end
rescue Timeout::Error => e
# the task took longer than 10 seconds
end
end
答案 3 :(得分:0)
不,没有办法做到这一点。如果你担心一个失控的工作,你肯定应该像Simone建议的那样把它包裹起来。然而,听起来你正在寻找更多的东西,但我不清楚你的最终目标。
用户永远不会有“取消”按钮的方法,因为这将涉及找到一种方法来直接与运行该作业的工作人员运行进程通信。可以向worker添加一个信号处理程序,这样你就可以执行kill -USR1 pid之类的操作,让它中止当前正在工作的作业并继续。这会实现你的目标吗?