讓我們從API開始。我想有以下的東西。
@available.working? # => true or false, so we know it's running
@available.finished? # => true or false, so we know it's finished (already ran)
現在讓我們來寫這份工作。
class AwesomeJob < Struct.new(:options)
def perform
do_something_with(options[:var])
end
end
到目前爲止好。我們有一份工作。現在讓我們編寫將它排入隊伍的邏輯。由於Available是負責這項工作的模型,讓我們教它如何開始這項工作。
class Available < ActiveRecord::Base
def start_working!
Delayed::Job.enqueue(AwesomeJob.new(options))
end
def working?
# not sure what to put here yet
end
def finished?
# not sure what to put here yet
end
end
那麼我們如何知道工作是否正常工作?有幾種方法,但在rails中,當我的模型創建某些東西時,它通常與此相關。我們如何聯繫?在數據庫中使用ID。讓我們在Available模型上添加一個job_id
。
雖然我們處於這個狀態,但我們如何知道這項工作是因爲工作已經完成或者尚未開工?一種方法是實際檢查工作實際上做了什麼。如果它創建了一個文件,請檢查文件是否存在。如果它計算出一個值,檢查結果是否寫入。有些工作不容易檢查,因爲他們的工作可能沒有明確的可證實的結果。對於這種情況,您可以在模型中使用標誌或時間戳。假設這是我們的情況,讓我們添加一個job_finished_at
時間戳來區分尚未運行作業從已完成一。
class AddJobIdToAvailable < ActiveRecord::Migration
def self.up
add_column :available, :job_id, :integer
add_column :available, :job_finished_at, :datetime
end
def self.down
remove_column :available, :job_id
remove_column :available, :job_finished_at
end
end
好的。所以,現在讓我們通過修改start_working!
方法,在我們排隊工作後立即將Available
與其工作聯繫起來。
def start_working!
job = Delayed::Job.enqueue(AwesomeJob.new(options))
update_attribute(:job_id, job.id)
end
太好了。在這一點上,我可以寫belongs_to :job
,但我們並不真的需要。
所以現在我們知道如何編寫working?
方法,這麼簡單。
def working?
job_id.present?
end
但是,我們如何標記工作完成?沒有人知道工作比工作本身更好。因此,讓我們將available_id
傳入作業(作爲選項之一)並將其用於作業。爲此,我們需要修改start_working!
方法來傳遞id。
def start_working!
job = Delayed::Job.enqueue(AwesomeJob.new(options.merge(:available_id => id))
update_attribute(:job_id, job.id)
end
而且我們應該添加邏輯到作業當它完成更新我們job_finished_at
時間戳。
class AwesomeJob < Struct.new(:options)
def perform
available = Available.find(options[:available_id])
do_something_with(options[:var])
# Depending on whether you consider an error'ed job to be finished
# you may want to put this under an ensure. This way the job
# will be deemed finished even if it error'ed out.
available.update_attribute(:job_finished_at, Time.current)
end
end
有了這個代碼在地方,我們知道該怎麼寫我們finished?
方法。
def finished?
job_finished_at.present?
end
我們完成了。現在我們只需輪詢@available.working?
和@available.finished?
此外,您還可以通過檢查@available.job_id
來獲知爲您的可用創建的確切工作的便利性。通過說belongs_to :job
可以很容易地將它變成真正的關聯。
我面對的另一個問題或障礙是,我正在抵消這項工作,因爲它會捆綁我的服務器。我詢問數據庫是否存在某些具有日期的數據,如果他們不存在或過期我獲取新數據,但將它作爲單獨的作業來使用,我使用AJAX,然後輪詢它直到完成...然後運行再次查詢新數據。希望更快,但也更復雜。 – holden 2011-04-13 20:00:36
是否會使用resque&redis之類的東西,並基本緩存返回的對象,爲數據庫節省額外往返時間並使輪詢速度更快?我從來沒有碰過redis或resque,所以我想我會把它扔到那裏。 – holden 2011-04-13 20:06:15