2013-12-10 46 views
2

我有以下代碼:如何找出一組Resque作業是否已完成?

[23, 45, 69, 20].each do |page_id| 
    Resque.enqueue(ProcessPage, page_id) 
end 

我想知道當所有這些工作都處理完畢後通過郵件通知用戶。我的第一個嘗試是在工作結束時通知用戶,但這對每項工作都是單獨工作的。

我發現這個寶石resque-status,這基本上讓你這樣做:

job_ids = [] 
[23, 45, 69, 20].each do |page_id| 
    job_ids << ProcessPage.create(page_id) 
end 

然後您可以通過檢查作業的狀態:

status = Resque::Plugins::Status::Hash.get(job_id) 

什麼混淆我是。 ..我應該什麼時候檢查所有狀態?我的意思是,我會在一段時間內檢查所有工作的狀態嗎?這將使服務器超時,任何想法我可以做到這一點?

+0

你會使用ajax或類似的東西 – phoet

+0

@phoet你是什麼意思?我多久會做一次AJAX調用以及爲什麼要這樣做?我需要通過電子郵件通知用戶。 –

+0

你沒有寫在你的問題。你可以開始另一項工作來檢查狀態。 – phoet

回答

3

我不打算在這裏粘貼任何代碼,因爲它看起來像你非常熟悉與應該如何寫作業,但想想下面的想法:

你應該有一個resque作業獲取和id數組處理。 此resque作業爲每個ID創建一個單獨的resque作業,以便它們將被並行處理。 爲特定的id創建resque作業後,它將創建另一個resque作業,獲取id列表並定期檢查它們以查看它們是否完成。完成後,此作業將向用戶發送電子郵件。

有了這個模式,你享受所有的世界:

  1. 每個ID都有自己的工作。
  2. 並行執行。
  3. 狀態檢查在後臺完成,因此用戶不會超時。

UPDATE:

的檢查resque工作的僞代碼:

class CheckerJob 
    @queue = :long 

    def self.perform(ids) 
    finished = [] 
    while finished.size < ids.size 
     ids.each do |id| 
     finished << id if job_finished?(id) 
     end 
     sleep 10 
    end 
    send_email_to_user 
    end 
end 

現在你剩下要做的一切都是爲了實現這兩個job_finished?(id)send_email_to_user方法。

+0

好的。這是有道理的,但是當你週期性地說,你是什麼意思?你能寫出這個「檢查」工作的樣子嗎? –

+0

添加了檢查器代碼應該如何的示例。 –

+0

謝謝。當你說平行執行時,這取決於我有多少工人對嗎?在這種情況下,你怎麼看待使用多線程範例? –

0

簡單的解決辦法是有你的工作採取ID列表:

Class Job 
    def self.perform(ids) 
    threads = ids.inject([]) do |memo, id| 
     memo << Thread.new { # whatever } 
    end 
    ThreadsWait.join_all(*threads) 
    # All threads are done 
    # Notify user that job is finished 
    end 
end 

別有檢查這一項是否已經完成的工作。如果你要去那種路線,訂閱Redis的事件http://redis.io/topics/internals-rediseventlib

UPDATE:增加了多線程

+0

如果我遵循這種方法,我會有一份可以做「X」工作的工作。這會讓「父母」工作極端緩慢,因爲我的每個「孩子」工作都需要相當長的時間... –

+0

然後使用多個線程 – Kaleidoscope

+0

您能否進一步解釋?我的意思是,我想到的是,在你的''''' #爲這個特定的ID創建一個新工作'''但是我有同樣的問題。我不知道什麼時候完成。 –

0

這樣做怎麼樣?

Resque.enqueue_to("page_processes#{user.id}", ProcessPage, page_id) 

#code in ProcessPageWorker below 
def self.perform(page_id, user_id) 
    #work 
    # code below notifies user if the 'page_processes' queue is equal to 1 
    notify_user if Resque.size("page_processes#{user_id}") == 1 
end 

我們將作業排入名爲'page_processes'的隊列加上用戶的ID。每完成一項工作,我們都會檢查「page_processes#{user_id}」隊列的大小。如果隊列等於1,則意味着正在處理的作業是隊列中的最後一個作業,所以我們應該通知用戶。我們在隊列名稱中包含user_id以確保隊列的唯一名稱。

讓我知道這是否有幫助。

+0

嗨,但我會有一個「命名」隊列爲每個用戶想要使用該API? –

+0

是的,您將擁有一個命名隊列,以便您稍後可以參考該隊列並檢查其大小(待處理作業的數量)。我更新了我的答案,將用戶的ID包含在隊列的名稱中,以便每個用戶都有自己的隊列。 – Gjaldon