2017-03-22 108 views
1

當我調用Controller中的路由時,我需要執行三項任務。現在我的代碼看起來像這樣(縮寫):Rails執行任務異步控制器

def set_quotas 

    TaskOne.new().ex 
    TaskTwo.new().ex 
    TaskThree.new().ex 

    quotas = @user.quotas 
    render json: quotas, status: 200, each_serializer: Api::V1::QuotaSerializer 
    end 

每個任務按順序運行。然而,其中有幾個呼籲外部服務。所以完成這個通話所需的總時間爲4-8秒,我們真的想要加快速度。

我想要做的是一起運行所有三個任務,但要等到每個任務完成後再執行json響應。在Rails中完成此操作的最佳方式是什麼?

回答

2

您可以使用threads

這裏有一個簡單的解決方案:

def set_quotas 
    [ 
    Thread.new { TaskOne.new().ex }, 
    Thread.new { TaskTwo.new().ex }, 
    Thread.new { TaskThree.new().ex } 
    ].each &:join 

    quotas = @user.quotas 
    render json: quotas, status: 200, each_serializer: Api::V1::QuotaSerializer 
end 

然而,有幾件事情要注意在Ruby中使用併發時的感覺。首先也是最重要的是,當你使用線程時,你將會面臨併發的所有複雜問題。期待頭痛。併發性可能會很快混淆簡單的任務。例如,對於您的問題,您需要確保您的三項任務是真正獨立的。一項任務是否依賴另一項任務的輸出?有沒有副作用?比方說,一個人是否會將一些數據寫入一個後續作業所依賴的數據庫?如果是這種情況,那麼上述方法將不起作用,您需要弄清楚如何適應其特​​定的相互依賴關係。

其次,紅寶石線程爲green threads。 (假設你正在使用MRI Ruby,而不是Rubinius或JRuby。)這意味着如果你只能通過ruby線程獲得某些任務的加速。幸運的是,網頁請求是而不是塊ruby線程,意味着上述解決方案併發所有請求。你應該看到這個解決方案的加速。

最後,這與您的使用案例有些特殊關係,當您的應用程序打電話給第三方時,通常是將這些內容歸類到工作人員的最佳做法。打給第三方的電話很容易出錯,並且它很快就會讓客戶返回400秒(500秒,如果你不小心錯誤處理!)。最好把這項工作放到一個隊列中,並給予客戶一個基本上說「得到請求,稍後再做」的迴應。

鑑於這一切,如果您發現您需要比原生ruby線程更強大的功能,請查看concurrent-ruby gem。

@ AbM的回答提到了Resque/DJ。有關更一般的解決方案,請查看ActiveJob。對於一些(但不是全部)變體,請參閱ActiveJob adapter list