Haskell Webserver: maintaining application state
Asked Answered
A

2

7

I'm trying to get more familiar with Haskell by developing web-app-ish services.

Say I'm developing a web-server and I want to keep persistent state between requests; a counter, for instance. What is the Haskell way of doing things?

I came across this discussion on my Google search. The proposed solution looks like a good example of what not to do.

One idea I had was having the request handler take in an MVar:

requestHandler :: MVar State -> IO (Maybe Response)

When registering the handler, it could be curried with an MVar created in main.

There must be a better way. I can't help but think I'm approaching this problem in a non-functional way.

Thanks!

Aila answered 25/1, 2013 at 19:19 Comment(5)
Why try to carry persistent state on the server itself? Seems to me Haskell would match much better with a RESTful design.Ossian
What's "non-functional" about that approach? You have some state you need to share, so you wrap it up and pass around the reference. Seems pretty straightforward to me.Mongeau
sclv: I'm wondering if there was more of a FRP approach.Aila
You say that you want a functional solution, but I suspect that you actually want a compositional solution.Chyou
Don't know if it is helpful but this is a example how I do it, github.com/gertcuykens/haskell-design let me know if it needs explanationVest
I
4

You probably want acid-state, which gives you that exactly: persistent state for Haskell data types. The documentation I linked even starts out with a request counter, just like you asked for.

Note that MVars are not persistent; the counter would get reset when the server is restarted. If that's actually the behavior you want I suggest you use a TVar instead; that way you can update the counter atomically without locks or the risk of deadlocks that go with them.

Interchangeable answered 26/1, 2013 at 16:10 Comment(0)
P
1

If you like persistence and TVars, you can use DBRefs, that have the same semantics and the same usage patterns as TVars. You must define a unique key for the state and you have automatic file persistence. For database persistence it is necessary to define an IResource instance.

The state will have a unique counter for each session:

import Data.Map as M
import Data.TCache
import Data.TCache.DefaultPersistence

type Counter= Int
type SessionId :: String
data State= State SessionId Counter deriving (Read, Show, Typeable)

instance Indexable State where
        key (State k _)= k 

requestHandler :: Request -> DBRef State -> IO (Maybe Response)
Protoplasm answered 27/4, 2013 at 10:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.