Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use yesod per-request caching?

I'm trying to use the cached function to prevent multiple db queries in different widgets and handlers:

newtype CachedBobId key
    = CachedBobId { unCachedBobId :: key }
    deriving Typeable

getBob' :: Handler BobId
getBob' = do
    uncle <- runInputGet $ ireq textField "bobsuncle"
    (Entity bob _) <- runDB $ getBy404 $ UniqueBob uncle
    return bob

getBob :: Handler BobId
getBob = do
    a <- getBob'
    let b = return $ CachedBobId a
    c <- cached b
    return $ unCachedBobId c

And in a widget somewhere:

renderDerp :: Widget
renderDerp = do
    --these are used in the shakespeare files
    lolBob <- handlerToWidget $ getBob
    nutherBob <- handlerToWidget $ getBob
    $(widgetFile "test")

This compiles but the query to get the ID still runs multiple times.

What am I doing wrong? Or is there a better way to only get bob once and use him in every handler and widget?

like image 651
user2936306 Avatar asked Nov 11 '15 16:11

user2936306


1 Answers

I'm pretty new to Yesod, but I think you just need to tweak getBob

getBob :: Handler BobId
getBob = unCachedBobId <$> cached (CachedBobId <$> getBob')

The problem is that your current getBob function starts its do block with a <- getBob'. Remember that a do block sequences monadic actions, so you actually end up calling getBob' first thing every time getBob is called. In an ironic twist, after you've done this, you create a cached version of a handler which returns what you just got from getBob', but end up querying that cached version exactly once (right afterwards with c <- cached b), then it just falls out of scope and the garbage collector gets it.

In the solution I present above, you wrap whatever getBob' gives you in CachedBobId. Then, you pass that handler CachedBobId <$> getBob' :: Handler (CachedBobId BobId), to cached, which gives you back another handler cached (CachedBobId <$> getBob') of the same type, but with caching. Finally, you extract whatever the cached handler gives you to get back a Handler BobId.

like image 87
Alec Avatar answered Oct 09 '22 12:10

Alec