0

我有一个像这样的方法,它通过一个数组来查找不同的 API,并delayed_job为每个像这样找到的 API 启动一个实例。

def refresh_users_list
  apis_array.each do |api| 
    api.myclass.new.delay.get_and_create_or_update_users
  end
end

我有一个after_filteronusers#index控制器来触发此方法。这创造了许多要触发的工作,最终会导致too many connectionsHeroku 出现问题。

我想知道是否有一种方法可以通过数组迭代的每个 API 检查数据库中是否存在作业。这将非常有帮助,因此如果该 api 在给定时间没有更新,我只能触发特定的刷新。

知道怎么做吗?

4

1 回答 1

1
  1. config/application.rb中,添加以下内容

    config.autoload_paths += Dir["#{config.root}/app/jobs/**/"]
    
  2. 在 处创建一个新目录app/jobs/

  3. 创建一个app/jobs/api_job.rb看起来像的文件

    class ApiJob < Struct.new(:attr1, :attr2, :attr3)
    
      attr_accessor :token
    
      def initialize(*attrs)
    
        self.token = self.class.token(attr1, attr2, attr3)
      end
    
      def display_name
        self.class.token(attr1, attr2, attr3)
      end
    
      #
      # Class methods
      #
      def self.token(attr1, attr2, attr3)
        [name.parameterize, attr1.id, attr2.id, attr3.id].join("/")
      end
    
      def self.find_by_token(token)
        Delayed::Job.where("handler like ?", "%token: #{token}%")
      end
    end
    

    注意:您将替换attr1, attr2, 和attr3您需要的任意数量的属性(如果有)传递给ApiJob以执行排队的任务。稍后详细了解如何调用它

  4. 对于您排队的每个 API,get_and_create_or_update_users您将创建另一个Job. 例如,如果我有一些Facebookapi 模型,我可能有一个app/jobs/facebook_api_job.rb看起来像的类

    class FacebookApiJob < ApiJob
      def perform
        FacebookApi.new.get_and_create_or_update_users(attr1, attr2, attr3)
      end
    end
    

    注意:在您的问题中,您没有将任何属性传递给get_and_create_or_update_users. 我只是向您展示如果您需要将属性传递给它的作业,您将在哪里执行此操作。

最后,无论你在哪里refresh_users_list定义,定义类似这个job_exists?方法的东西

def job_exists?(tokens)
  tokens = [tokens] if !tokens.is_a?(Array) # allows a String or Array of tokens to be passed

  tokens.each do |token|
    return true unless ApiJob.find_by_token(token).empty?
  end

  false
end

现在,在您的refresh_users_listand 循环中,您可以构建新的令牌并调用job_exists?以检查您是否为 API 排队作业。例如

# Build a token

def refresh_users_list
  apis_array.each do |api| 
    token = ApiJob.token(attr1, attr2, attr3)
    next if job_exists?(token)

    api.myclass.new.delay.get_and_create_or_update_users
  end
end

注意:我想再次指出,你不能只输入上面的代码并让它工作。您必须根据您的应用程序和您正在运行的工作对其进行定制。


为什么这么复杂?

根据我的研究,没有办法通过delayed_job提供的内容来“标记”或唯一标识排队的工作。当然,每个工作都有一个独特的:id属性。您可以将每个创建的作业的 ID 值存储在某个散列中

{
  "FacebookApi": [1, 4, 12],
  "TwitterApi": [3, 193, 44],
  # ...
}

然后检查相应的哈希键的 ID,但我发现这个限制,并不总是足够的问题当您需要通过多个属性识别特定作业时,我们必须创建一种方法来查找这些作业无需加载每个将作业放入内存并循环遍历它们以查看是否符合我们的标准)

这是如何工作的?

extends 有一个Struct属性。此标记基于传递的属性( , , ) ,并在实例化新扩展类时构建。ApiJob:tokenattr1attr2attr3ApiJob

类方法只是根据使用相同类方法构建的令牌find_by_token在队列中搜索作业的字符串表示以查找匹配项。delayed_jobtoken

于 2012-12-13T00:05:18.717 回答