在Scotty Server中分叉新线程

时间:2017-06-14 18:45:53

标签: haskell monad-transformers scotty

我正在使用两个API为Scotty中的Web服务器进行原型设计:

  • /add/:id使用给定的Id启动asyc任务。
  • /cancel/:id杀死给定身份证的任务。

基本上,客户端通过提供一些ID来启动异步任务,并且还可以通过其ID来杀死当前任务。

我使用Control.Concurrent.forkIO来启动一个帖子,forkIO返回我存储在Scotty全局状态中的ThreadId,这是一个Map:type AppState = Map TaskId ThreadId

/add/:id不会立即返回,但它等待任务完成并将结果返回给客户端。

我的问题是将forkIOMonadIO m => ActionT Text m ()混合。我需要能够在完成text :: Text -> ActionT Text m () IO ()后的forkIO行动后致电MonadIO m

这需要从IO转到import qualified Control.Concurrent as C import qualified Control.Concurrent.STM as STM import Control.Monad.Trans.Reader (ReaderT(..), runReaderT) import Control.Monad.Trans (MonadIO) import Control.Monad.Reader (MonadReader, lift, liftIO, ask) import qualified Data.Map as M import Data.Text.Lazy (Text, pack, unpack) import Web.Scotty.Trans type TaskId = String type AppState = M.Map TaskId C.ThreadId newtype WebM a = WebM { runWebM :: ReaderT (STM.TVar AppState) IO a } deriving (Applicative, Functor, Monad, MonadIO, MonadReader (STM.TVar AppState)) app :: ScottyT Text WebM () app = do get "/add/:id" $ do taskId <- fmap unpack (param "id") let task = return "Hello World" -- just a dummy IO tid <- liftIO $ C.forkIO $ do result <- task -- Couldn't match type ‘ActionT Text m’ with ‘IO’ lift $ modify' $ M.delete taskId -- remove the completed task from the state text result -- return the result to the client return () -- forkIO :: IO () -> IO ThreadId lift $ modify' $ M.insert taskId tid -- immedialtey add the new task to the state get "/cancel/:id" $ do taskId <- fmap unpack (param "id") dic <- lift $ gets id maybe (text $ pack (taskId ++ " Not Found")) ( \ tid -> do liftIO $ C.killThread tid lift $ modify' $ M.delete taskId -- remove the cancelled task from the state text $ pack (taskId ++ " Cancelled") ) (M.lookup taskId dic) gets :: (AppState -> b) -> WebM b gets f = fmap f (ask >>= liftIO . STM.readTVarIO) modify' :: (AppState -> AppState) -> WebM () modify' f = ask >>= liftIO . STM.atomically . flip STM.modifyTVar' f main :: IO () main = do dic <- STM.newTVarIO M.empty let runActionToIO m = runReaderT (runWebM m) dic scottyT 3000 runActionToIO app 这显然是一个错误,但我无法理解它并找到任何解决方案。

这是完整的例子:

import time
def random_digits(y):
    return int(time.time())

1 个答案:

答案 0 :(得分:3)

我认为你需要从分叉线程中调用text result,并在结果准备好时使用MVar进行通信。像

这样的东西
get "/add/:id" $ do
    taskId <- fmap unpack (param "id")
    let task = return "Hello World"
    m <- newEmptyMVar
    tid <- liftIO $ C.forkIO $ do
        result <- task
        putMVar result
        ...
    r <- takeMVar m
    text r

takeMVar将阻止,直到MVar包含值。