提问者:小点点

保持后台进程在 Heroku 上运行


我试图在heroku上运行rabbitmq后台进程,从队列中挑选任务并处理它们。我正在与AMQP·哈斯克尔库合作,他们给出了下面的例子(为了简洁,省略了一些部分。

main = do
    --setup connection omitted
    --connect to queue, wait for messages
    consumeMsgs chan "myQueue" Ack myCallback
    --halts process so messages are taken off the queue until a key is presseed
    getLine -- wait for keypress
    closeConnection conn -- close connection after key
    putStrLn "connection closed"

这在本地工作正常,因为 getLine 保持进程运行,直到您按下某个键。但是,当我将其部署到 heroku 时,进程退出

2016-04-19T08:37:23.373087 00:00 app[worker.1]: worker:

我从这个问题的公认答案中发现,这是因为为了通过ssh部署后台进程,您需要将/dev/null/重定向到stdin,它会向进程发送EOF信号。

在我们的例子中,getLine函数因为这个信号而退出,整个过程停止,防止我们的工作人员熬夜。

我如何在部署时保持该工作人员运行?

编辑:最终解决方案 使用@carstons评论,我最终得到了以下有效的实现:

main :: IO ()
main = do
    mvar <- newEmptyMVar
    conn <- setupConnection
    queueName <- pack <$> getEnv "QUEUE_NAME"
    chan <- openChannel conn
    consumeMsgs chan queueName Ack processMessage
    installHandler sigINT (Catch (cleanupConnection conn mvar)) Nothing
    putStrLn "Running forever, press ctrl c to exit"
    -- this blocks until sigint is recieved and the handler for SIGINT
    -- "fills" the mvar. once that is filled the process exits
    run <- takeMVar mvar
    case run of
      _ -> return ()

mixpanelConfig :: IO Config
mixpanelConfig = liftM2 Config (ApiToken . pack <$> getEnv "MIXPANEL_API_TOKEN") (newManager tlsManagerSettings)

cleanupConnection :: Connection -> MVar () -> IO ()
cleanupConnection conn mvar = do
  closeConnection conn
  putStrLn "SIGINT received.. closing rabbitmq connection"
  putMVar mvar ()

processMessage :: (Message, Envelope) -> IO ()

共1个答案

匿名用户

正如我在评论中指出的那样,如果你只是想让它永远运行,你可以使用forever和-例如-threadDelay

import Control.Concurrent (threadDelay)
import Control.Monad (forever)

main = do
    --setup connection omitted
    --connect to queue, wait for messages
    consumeMsgs chan "myQueue" Ack myCallback
    --halts process so messages are taken off the queue forever
    forever $ threadDelay 10000
    -- so this will never happen and you could remove it
    closeConnection conn -- close connection after key
    putStrLn "connection closed"

请注意,这当然永远不会真正关闭连接或退出应用程序-您必须终止该进程。

另一种可能会更复杂一些,因为你需要一些消息/方法来给你的程序发送一个终止信号。

一种简单的方法是使用< code>MVar,当在队列中收到某个stop消息时,可以在< code>myCallback中设置它:

import Control.Concurrent.MVar

main = do
    -- MVar to receve the quit-signal
    quitSignal <- newEmptyMVar
    --setup connection omitted
    --connect to queue, wait for messages - the callback should
    --set the quitSignal with putMVar quitSignal ()
    consumeMsgs chan "myQueue" Ack (myCallback quitSignal)
    --halts process so messages are taken off the queue till quitSignal
    takeMVar quitSignal
    -- so this will happen after quitSignal was set
    closeConnection conn -- close connection after key
    putStrLn "connection closed"