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_filteronコントローラーがあります。users#indexこれにより、トリガーされる多くのジョブが作成され、最終的too many connectionsにHerokuで問題が発生します。

配列が繰り返す各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置き換えます。これをすぐに呼び出す方法の詳細attr2attr3ApiJob

  4. いくつかのget_and_create_or_update_usersメソッドをキューに入れるAPIごとに、別のメソッドを作成します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

これで、andループ内で、refresh_users_list新しいトークンを作成し、呼び出し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 に答える