在Rails中安排和执行重复任务(比如抓取信息页面)的最佳方法是什么?

时间:2013-11-20 13:28:13

标签: ruby-on-rails ruby nokogiri rufus-scheduler

我正在寻找能够实现的解决方案:

  1. 重复执行抓取任务(nokogiri)
  2. 通过http://www.myapp.com/interval更改时间间隔(示例)
  3. 完成这项工作的最佳解决方案/方法是什么?

    我了解的选项

    • 自定义佣金任务
    • Rufus Scheduler

    现状

    ./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中使用?

2 个答案:

答案 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,例如在控制器中。

有哪些可能的选项,而不是类变量:

  • 从配置文件中读取
  • 从数据库中读取它(但您必须设置自己的连接,在初始化程序中,activerecord未启动imho

并且......如果您更改了值,则必须重新启动rails进程才能再次生效。

因此,一种替代方法,即rails进程处理预定作业的间隔,就是使用重复的后台作业。在背景的最后,它重新安排自己,在那一刻活跃的间隔。我建议从数据库中提取间隔。 任何后台作业处理程序都可以这样做检查ruby toolbox,我投票给resque或delayed_job。