2013-06-20 52 views
2

我正在開發一個Yesod應用程序,其中許多應用程序請求將導致從第三方API獲取數據。獲取的數據只會在後續請求中使用 - 也就是說,觸發API標註的請求可以在不等待標註完成的情況下完成。單獨的'App'和'BackgroundJobs'包的佈局

重要的是,某個數據段xyz不會被提取和存儲兩次,但應用程序的性質是,多個客戶端通常會在同一時刻對xyz產生興趣。如果我有每個應用程序線程查詢數據庫以查看xyz是否已被提取,那麼即使規模不大,我也會開始查看併發相關問題。即使我要編寫一堆代碼來處理併發相關的完整性問題 - 並不好玩,並且很難確定我是否覆蓋了所有情況 - 這樣濫用昂貴的數據庫查詢是不好的做法。

在我看來,一個好的選擇是讓所有的App線程將請求發送到一個AMQP隊列(「確保xyz數據已被提取」),一個或多個「後臺工作者」 。

this thread格雷格韋伯建議雙包裝佈局,其中兩個包都有'我的持久層'作爲依賴。他提到我可以使用符號鏈接或hs-source-dir來避免維護'持久層'代碼的兩個副本。

格雷格描述的高水平對我來說很合理,但我對哈斯克爾來說比較新,我擔心這需要我花些時間才能弄清楚細節。有人可以爲我更詳細地介紹它嗎?

  • 包目錄應該如何佈置? (哪些文件正好構成了我的持久層?)
  • .cabal文件應該是什麼樣子?
  • 一旦他們這樣佈局,我是否需要改變我的(腳手架網站)源文件導入我的持久模型的方式?

另一部分是:你會如何推薦編寫BackgroundJobs過程?除了Yesod的腳手架之外,我從未寫過生產Haskell代碼。我在大致的概述中得到它 - 我只寫一個main,我將在其中訂閱消息隊列,並在每條消息上執行我的調出/處理/存儲 - 但是我是否需要擔心手動分叉以確保在等待標註結束時該過程不會阻止?

非常感謝。

回答

1

我不在起跑線上,使用Erik建議的一般方法 - 我只是在腳手架項目的.cabal文件中添加了第二個executable塊。這裏的(在Erik的製劑「daemon.hs」)對應的源文件:我基於它上this Yesod wiki entry第一示例

{-# LANGUAGE OverloadedStrings #-} 
module Main where 

import Import 
import Yesod.Default.Config 
import qualified Database.Persist 
import qualified Database.Persist.Store as DPS (runPool, createPoolConfig, loadConfig, applyEnv) 
import Settings 
import Model 
import Data.Conduit (runResourceT) 
import Control.Monad.Logger (runStdoutLoggingT) 
import Debug.Trace 
import Data.Text as T 

runQueries = do 
    res <- getBy $ UniqueFoo "bar" 
    trace ("\nresult: " ++ show res ++ "\n\n") $ return() 

main :: IO() 
main = do 
    conf <- (fromArgs parseExtra) 
    dbconf <- withYamlEnvironment "config/postgresql.yml" (appEnv conf) 
       DPS.loadConfig >>= DPS.applyEnv 
    p <- DPS.createPoolConfig (dbconf :: Settings.PersistConfig) 
    runStdoutLoggingT $ runResourceT $ DPS.runPool dbconf runQueries p 

- 修飾使得可執行期望的環境標誌。

+0

順便說一下,這是使用Yesod 1.19。我已經更新到1.2,並且需要對這些代碼進行一些微調 - 所有這些都很簡單/明顯。 –

2

我有一個應用程序,它由一個web應用程序和一個單獨的守護進程組成,它收集數據並將其插入到與web應用程序共享的數據庫中。

我基本上擁有相同源代碼樹中的所有代碼,並且有兩個文件定義main :: IO(),一個名爲webapp.hs,另一個名爲daemon.hs。然後我有cabal文件定義和構建兩個單獨的可執行文件。

不幸的是,我不能將代碼作爲我在日常工作中做的內部項目來分享。