title: keeping a background process running on heroku
body: <p>I'm trying to run a rabbitmq background process on heroku to pick tasks off a queue and process them. I'm working with the AMQP haskell library and they give the following <a href="https://hackage.haskell.org/package/amqp-0.13.0/docs/Network-AMQP.html" rel="nofollow noreferrer">example</a> (parts omitted or brevity.</p>
  
  <pre><code>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"
  </code></pre>
  
  <p>This works fine locally because <code>getLine</code> keeps the process running until you press a key. However, when I deploy this to heroku the process exits with</p>
  
  <p><code>2016-04-19T08:37:23.373087+00:00 app[worker.1]: worker: &lt;stdin&gt;: hGetChar: end of file</code></p>
  
  <p>I figured out from <a href="https://stackoverflow.com/questions/19955260/what-is-dev-null-in-bash">the accepted answer to this question</a> that this is because in order to deploy a background process via ssh you need to redirect <code>/dev/null/</code> to <code>stdin</code> which sends an <code>EOF</code> signal to the process.</p>
  
  <p>In our case the <code>getLine</code> function exits because of this signal and the entire process stops, preventing our worker from staying up.</p>
  
  <p>How can I keep this worker running when I deploy?</p>
  
  <p><strong>EDIT: Final Solution</strong>
  Using @carstons comments I ended up with the following implementation that worked:</p>
  
  <pre><code>main :: IO ()
  main = do
      mvar &lt;- newEmptyMVar
      conn &lt;- setupConnection
      queueName &lt;- pack &lt;$&gt; getEnv "QUEUE_NAME"
      chan &lt;- 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 &lt;- takeMVar mvar
      case run of
        _ -&gt; return ()
  
  mixpanelConfig :: IO Config
  mixpanelConfig = liftM2 Config (ApiToken . pack &lt;$&gt; getEnv "MIXPANEL_API_TOKEN") (newManager tlsManagerSettings)
  
  cleanupConnection :: Connection -&gt; MVar () -&gt; IO ()
  cleanupConnection conn mvar = do
    closeConnection conn
    putStrLn "SIGINT received.. closing rabbitmq connection"
    putMVar mvar ()
  
  processMessage :: (Message, Envelope) -&gt; IO ()
  </code></pre>