完成这项工作的最佳解决方案/方法是什么?
在./config/initializers/task_scheduler.rb
我有:
require 'nokogiri'
require 'open-uri'
require 'rufus-scheduler'
require 'rake'
scheduler = Rufus::Scheduler.new
scheduler.every "1h" do
puts "BEGIN SCHEDULER at #{Time.now}"
@url = "http://www.marktplaats.nl/z/computers-en-software/apple-ipad/ipad-mini.html? query=ipad+mini&categoryId=2722&priceFrom=100%2C00&priceTo=&startDateFrom=always"
@doc = Nokogiri::HTML(open(@url))
@title = @doc.at_css("title").text
@number = 0
2.times do |number|
@doc.css(".defaultSnippet.group-#{@number}").each do |listing|
@listing_title = listing.at_css(".mp-listing-title").text
@listing_subtitle = listing.at_css(".mp-listing-description").text
@listing_price = listing.at_css(".price").text
@listing_priority = listing.at_css(".mp-listing-priority-product").text
listing = Listing.create(title: "#{@listing_title}", subtitle: "#{@listing_subtitle}", price: "#{@listing_price}")
end
@number +=1
end
puts "END SCHEDULER at #{Time.now}"
end
是的,当前设置正常。但是,我不知道如何通过http://www.myapp.com/interval(示例)启用更改间隔时间。
将scheduler.every "1h"
更改为scheduler.every "#{@interval} do
不起作用。
我必须在哪个文件中定义@interval
才能在task_scheduler.rb
中使用?
答案 0 :(得分:2)
我对Rufus Scheduler不是很熟悉,但似乎很难实现你的两个目标(常规心跳,动态重新安排)。为了使其工作,您必须捕获它返回的job_id,如果发生重新安排事件,则使用该job_id停止作业,然后创建新作业。 Rufus还指出它是一个内存中的应用程序,当进程消失时,它的工作将会消失 - 重新启动服务器,重启应用程序等等,你必须从头开始重新安排。
我会考虑两件事。首先,我会考虑创建一个包含你想要做的屏幕抓取的模型。至少你会捕获网址和间隔。该模型可以将用于处理html响应的代码(基本上包含在2.times块中的内容)包装为基于URL触发的实例方法。您也可以在文本列中捕获它并在其上使用eval,假设只有“好人”可以访问系统的这一部分。这有几个优点:您可以快速扩展到抓取其他站点,并且可以清理用户发回的间隔。
其次,像Delayed :: Job这样的东西可能更适合你的需求。 Delayed :: Job允许您指定作业执行的时间,您可以通过阅读模型并将时间间隔转换为时间来填写。这种方法的关键是作业必须在退出之前安排下一次迭代。
这不像cron那样坚如磐石,但似乎更能满足重新安排的需要。
答案 1 :(得分:1)
首先关闭:你的rufus调度程序代码在初始化程序中,这很好,但是它在rails进程启动之前执行,而仅在启动rails进程时执行。因此,在初始化程序中,您无法访问可以设置的任何变量@interval
,例如在控制器中。
有哪些可能的选项,而不是类变量:
并且......如果您更改了值,则必须重新启动rails进程才能再次生效。
因此,一种替代方法,即rails进程处理预定作业的间隔,就是使用重复的后台作业。在背景的最后,它重新安排自己,在那一刻活跃的间隔。我建议从数据库中提取间隔。 任何后台作业处理程序都可以这样做检查ruby toolbox,我投票给resque或delayed_job。