たとえば、10分で実行するジョブをスケジュールしています。モデルなどでダーティな余分なフィールドを使用せずに、この特定のジョブを適切にキャンセルする方法。特定のジョブ、または特定のモデル、インスタンスなどに関連するジョブを削除するための呼び出しはありますか?
4 に答える
免責事項:私はdelayed_jobのエキスパートユーザーではありません...
「特定のジョブ、または特定のモデル、インスタンスなどに関連するジョブを削除するための呼び出しはありますか?」
Delayed :: Jobは単なるActiveRecordオブジェクトなので、これらのレコードを見つけて破棄することができます。ユースケースに応じて、これはさまざまな方法で処理できます。誰かが手動でそれらを破棄しようとしている場合、これはWebアプリの管理インターフェースを介して処理できます。
# list all jobs
Delayed::Job.all
# find a job by id
job = Delayed::Job.find(params[:id])
# delete it
job.delete
「ジョブタイプ」ごとにジョブを削除するプロセス外のタスクが必要な場合は、それぞれをループして、ジョブと一致する場合は削除できます。スクリプト/コンソールでこれを試してください
class MyJob < Struct.new(:some_value);
def perform
# ...
end
end
my_job = MyJob.new('xyz')
job = Delayed::Job.enqueue(my_job, 0, 1.hour.from_now)
job.name
# => "MyJob"
job.handler
# => "--- !ruby/struct:MyJob \nsome_value: xyz\n"
MyJobタイプのすべてのジョブを削除する場合は、上記のようになります。
Delayed::Job.all.each do |job|
if job.name == "MyJob" then
job.delete
end
end
これはあなたの状況に役立つかもしれませんし、そうでないかもしれませんか?多くの場合、MyJobを削除したい場合がありますが、:some_value属性が「xyz」ではなく「abc」である場合のみです。この場合、MyJobオブジェクトに「display_name」を実装する必要があるかもしれません。job.nameは、存在する場合はこれを使用します
class MyJob < Struct.new(:user_id);
def perform
# ...
end
def display_name
return "MyJob-User-#{user_id}"
end
end
# store reference to a User
my_job = MyJob.new(User.first.id) # users.id is 1
job = Delayed::Job.enqueue(my_job, 0, 1.hour.from_now)
job.name
# => "MyJob-User-1"
job.handler
# => "--- !ruby/struct:MyJob \nuser_id: 1\n"
このようにして、削除するレコードをより選択的にすることができますか?
うまくいけば、これはあなたにそれを処理するための可能な方法に関する十分な情報を与えるのですか?
delayd_job3はqueue
属性を導入しました。これを乗っ取って、キャンセル可能なジョブをスケジュールすることができます。
class MyJob < Struct.new(:user_id)
def self.queue_name
"something-unique"
end
def perform
# ...
end
end
#scheduler
my_job = MyJob.new(User.first.id)
#'cancel' pending jobs first
Delayed::Job.where(queue: my_job.class.queue_name).destroy_all
#queue it up
Delayed::Job.enqueue(my_job,
queue: my_job.class.queue_name,
run_at: 1.hour.from_now
)
渡されたパラメーターのみを使用してジョブを探している場合は、遅延ジョブのpayload_objectメソッドの使用を検討することもできます。
Delayed::Job.all.each do |job|
job.destroy if job_corresponds_to_target?(job, target)
end
def job_corresponds_to_target?(job, target)
job.payload_object.args.first == target.id
end
このsimplistの例では、返されたpayload_objectを完全には使用していません。
=> #<Delayed::PerformableMethod:0x0056551eae3660 @object=ReminderMailJob, @method_name=:perform_later, @args=[3]>
特にキューが大きい場合(たとえば、rails eventstoreが、ジョブをスケジュールするためにサブスクライブしたイベントを再生する場合)、キューに入れられたすべてのジョブのシリアル化フィールド(:handler)をループするのはコストがかかると思います。
したがって、手術を避けて私にとってうまくいくと思われる解決策は、次のようになります。
# some_specific_event_handler.rb or policy
record_uuid = SomeModel.find(event.data[:id]).uuid
queue_name = "#{record_uuid}_update_notification"
Delayed::Job.where(queue: queue_name).destroy_all
UpdateNotificationJob.set(
wait: 30.minutes,
queue: queue_name,
).perform_later(record_uuid)
Delayed::JobはDelayed::Backend::ActiveRecordです
:queueフィールドは任意の文字列です。あなたのコードがそれを使って何かをしない限り、その値はいつどのようにジョブが実行されるかには何の役割も果たさないと思います。
そこで、アプリロジックをその:queueフィールド値にフックしました。これは私の場合、要件によって機能しました。
- 新しいイベントが発生した場合は、ジョブをスケジュールします
- このイベントに同じクラスのジョブがスケジュールされていた場合は、それらをダンプします。