[Haskell-cafe] Application Level server state in Haskell Web
server
Pieter Laeremans
pieter at laeremans.org
Sun Feb 18 09:03:34 EST 2007
Thanks for your response.
There 's one thing I don't understand however: the countRef function
returns the same MVar all the time.
What 's the reason for that ? I would expect that every time that
function is invoked, it returns a new MVar,
but clearly it does not.
From the documentation of unsafePerformIO
Use {-# NOINLINE foo #-} as a pragma on any function foo that calls
unsafePerformIO. If the call is inlined, the I/O may be performed
more than once.
I try to conclude that writing the Pragma NOINLINE somehow makes
sure that the result of countRef is computed only once! And
subsequent invocations of the function will return the same result.
In a way this makes sense because a function that is invoked twice
with the same arguments "computes" the same result.
But, somehow it is a very nasty hack.
Am I getting it, or am I completly wrong ?
kind regards,
Pieter
On 18-feb-07, at 03:26, Donald Bruce Stewart wrote:
> pieter:
>> Hello,
>>
>> I'm trying to write a simple module for the haskell web server (hws-
>> cgi).
>>
>> And I would like to write a simple module that maintains some kind of
>> state for a session.
>>
>> But I'm I write I cannot do this in pure Haskell ? Without adopting
>> the sources of the Haskell web server ?
>>
>> I'll examplify to make it more concrete :
>>
>> The requestHandler function a module has to implement has this
>> signature.
>>
>> requestHandler :: ServerState -> ServerRequest -> IO (Maybe
>> Response)
>>
>> Let 's assume I have this implementation
>>
>> requestHandler st _ = return $ Just $ mkRequest
>> where mkRequest =
>> okResponse (serverConfig st) mkBody hs True
>> mkBody = HereItIs " This is a test"
>> hs = mkHeaders [contentTypeHeader "text/html"]
>>
>> And I would like the response to include, for example, a number
>> indicating the number of calls that has been handled by the module.
>>
>> I would concider using an Mvar but I can't "remember" the mvar
>> between requests.
>>
>> Am I right to assume that the interface of the requestHandler method
>> has to be adapted ? Or that serverstate has to be adopted so that it
>> can act as a datastore ?
>
> I don't think so.
>
> You could, for example store the count on disk, and read it back
> in. Or
> you could simulate a disk store by using a mutable variable, hidden in
> your module:
>
>
> module M (requestHandler) where
>
> import Control.Concurrent.MVar
> import System.IO.Unsafe
>
> --
> -- A threadsafe mutable variable, internal to this module. Rather
> -- than use, say, a disk file as storage, we can keep the count
> here.
> --
> countRef :: MVar Int
> countRef = unsafePerformIO $ newMVar 0
> {-# NOINLINE countRef #-}
>
>
> ----------------------------------------------------------------------
> --
> -- And a quick example:
>
> type Response = Int
>
> requestHandler :: IO (Maybe Response)
> requestHandler = do
> n <- modifyMVar countRef $ \c -> return (c+1, c)
> print $ "received " ++ show n ++ " requests."
> return $ case n of
> 0 -> Nothing
> _ -> Just n
>
>
>
> *Main> requestHandler
> "received 0 requests."
> Nothing
>
> *Main> requestHandler
> "received 1 requests."
> Just 1
>
> *Main> requestHandler
> "received 2 requests."
> Just 2
>
> *Main> requestHandler
> "received 3 requests."
> Just 3
>
>
> This seems simpler than writing the count to disk. And as long as you
> stay in IO, perfectly safe.
>
> In the longer term, you might want to look at state-parameterised
> plugins for the HWS. We do this in lambdabot, associating a private
> state type with each plugin, which is managed by the main server. The
> plugins can then get or set internal state, without resorting to local
> mutable variables.
>
> -- Don
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070218/2ffc2ece/attachment-0001.htm
More information about the Haskell-Cafe
mailing list