Thread-safe state with Warp/WAI
concurrency, haskell, haskell-wai, haskell-warp, state
Solution
If your interaction with the state can be expressed with a single call to `atomicModifyIORef`, you can use that, and you don't need to explicitly serialise access to the state.
import Data.IORef
main = do state <- newIORef 42
run 3000 (app' state)
app' :: IORef Int -> Application
app' ref req
= return . text . pack . show `liftM` atomicModifyIORef ref (\st -> (st + 1, st + 1))
If your interaction is more complex and you need to enforce full serialisation of requests, you can use an `MVar` in conjunction with `StateT`.
import Control.Concurrent.MVar
import Control.Monad.State.Strict
main = do state <- newMVar 42
run 3000 (app' state)
app' :: MVar Int -> Application
app' ref request
= do state <- takeMVar ref
(response, newState) <- runStateT (application request) state
putMVar newState --TODO: ensure putMVar happens even if an exception is thrown
return response
application :: Request -> StateT Int (ResourceT IO) Response
application request = modify (+1) >>= return . text . pack . show
Problem
I want to write a web server which stores its state in a `State` monad with `wai`/`warp`. Something like this: ``` {-# LANGUAGE OverloadedStrings #-} import Network.Wai import Network.Wai.Handler.Warp import Network.HTTP.Types import Control.Monad.State import Data.ByteString.Lazy.Char8 main = run 3000 app text x = responseLBS status200 [("Content-Type", "text/plain")] x app req = return $ text "Hello World" app1 req = modify (+1) >>= return . text . pack . show -- main1 = runStateT (run 3000 app1) 0 ``` The commented line doesn't work, of course. The intent is to store a counter in a state monad and display its increasing value on every request. Also, how do I get thread safety? Does warp run my middleware sequentially or in parallel? What options are available for the state - is there anything at all besides `IORef` I can use in this scenario? I understand that State gives safety but it seems wai doesn't allow State. I only need a dead-simple single-threaded RPC I can call from somewhere else. `Haxr` package requires a separate web server which is an overkill. See Calling Haskell from Node.JS - it didn't have any suggestions so I wrote a simple server using Wai/Warp and Aeson. But it seems that WAI was designed to support concurrent implementatons so it complicates things.