2015-11-17 22 views
0

在我屈web應用程序,我有一個路線:運行的時候可以

get "/" do 
    temp = MyClass.new("hello",1) 
    redirect "/home" 
end 

其中MyClass是:

class MyClass 
    @instancesArray = [] 
    def initialize(string,id) 
     @string = string 
     @id = id 
     @instancesArray[id] = this 
    end 
    def run(id) 
     puts @instancesArray[id].string 
    end 
end 

在某些時候,我會想運行MyClass.run(1),但我不會」不希望它立即執行,因爲這會降低服務器對某些客戶端的響應速度。我希望服務器等待運行MyClass.run(temp),直到有一段時間輕負載。我怎麼能告訴它等到空載/輕載,然後運行MyClass.run(temp)?我可以這樣做嗎?

附錄

這裏是我想要做一些示例代碼:

$var = 0 

get "/" do 
    $var = $var+1 # each time a request is recieved, it incriments 
end 

之後,我將有一個循環,將計算請求/分鐘(所以一分鐘後,將$var重置爲0,並且如果$var小於某個數字,則它將運行任務利用負載增加。

回答

0

MyClass.run(temp)永遠不會實際執行。我們當前請求/路徑您實例化一個MyClass的新實例,那麼它會立即向/home發出get請求。我不完全確定問題是什麼。如果您希望在重定向後執行某些操作,則該功能需要存在於/home路由中。

get '/home' do 
    # some code like MyClass.run(some_arg) 
end 
+0

奧普抱歉!錯字!這可能是更好的評論。我現在已經解決了問題。 – thesecretmaster

2

安德魯提到的(正確的,不知道爲什麼他被否決),西納特拉stops處理路線時,看到一個redirect,所以任何後續語句永遠不會執行。如您所述,您不希望在之前將這些陳述置於redirect之前,因爲這會阻止請求直至完成。您可能會將重定向狀態和標頭髮送到客戶端,而不使用方法redirect,然後調用MyClass#run。這將會產生所需的效果(從客戶端的角度來看),但服務器進程(或線程)會阻塞,直到完成。這是不可取的,因爲該進程(或線程)在解除阻塞之前將無法提供任何新請求。

你可以派生一個新的進程(或產生一個新的線程)來處理這個後臺任務異步處理與請求相關的主進程。不幸的是,這種方法有可能變得混亂。你將不得不圍繞不同的情況進行編碼,比如後臺任務失敗,或者失敗,或者主請求進程沒有結束,如果它擁有正在運行的線程或其他進程。 (免責聲明:我不太瞭解IPC和Ruby在不同應用程序服務器下的IPC,以瞭解所有不同的場景,但我相信在這裏會有龍。)

最常見的解決方案模式這種類型的問題是推動任務進入某種工作隊列,稍後由另一個進程提供服務。理想情況下,將任務推入隊列是一項非常快速的操作,並且不會在幾毫秒內阻塞主進程。這引出了一些新的挑戰(隊列在哪裏?如何描述任務以便在稍後沒有任何上下文的情況下提供便利?我們如何維護工作流程?)幸運的是,其他人已經完成了很多腿部工作。 :-)

有一個delayed_job寶石,它似乎提供了一個很好的一體化解決方案。不幸的是,它主要面向Rails和ActiveRecord,過去人們爲了與Sinatra合作而做的努力看起來沒有保持。當代,框架不可知的解決方案是ResqueSidekiq。啓動和運行任何一個選項都需要一些努力,但如果在應用程序中有幾個「可以運行」類型的函數,那將是非常值得的。

+0

我實際上已經看到了工作隊列解決方案,並且正在尋找更好的方法,因爲工作隊列解決方案仍然會減慢下一個請求的速度,因爲服務器將很忙且可用的資源較少。但+1的偉大的詳細答案!我一定會考慮這個寶石,因爲它似乎是我最有前途的解決方案。 – thesecretmaster

+0

但是我也在尋找的是一種在服務器流量減少時運行的方式。所以我需要一些能夠追蹤流量的東西,當服務器上的負載較輕時,它會執行任務。 – thesecretmaster

+0

最簡單的方法是用'nice'運行後臺進程,這會向內核提示以低優先級運行該命令。 – mwp