| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Freckle.App.GlobalCache
Description
Facility for purely creating an IORef in which to stash a value
Storing a truly global value can be useful for performance (e.g. to speed up
tests by caching a constructed App) or necessary to prevent contention (e.g.
by caching a single LoggerSet which holds access to a log file).
In some cases, it's not possible to create an IORef safely in an IO
context to use for this purpose. Either because a library prevents it (e.g.
the test runner provides no such hook before triggering its parallel
execution) or because the current application architecture cannot allow it
without a high effort re-organization.
For these cases, we use this module.
Usage
Given some function,
makeLogger :: HasLogging a => a -> IO Logger
makeLogger app = makeYesodLogger =<< newLoggerSet defaultBufSize
where
newLoggerSet = case getLogLocation app of
LogStdout -> newStdoutLoggerSet
LogStderr -> newStderrLoggerSet
LogFile f -> flip newFileLoggerSet f
Update it to cache the construction in a new top-level value,
loggerSetVar :: GlobalCache LoggerSet
loggerSetVar = unsafePerformIO newGlobalCache
{-# NOINLINE loggerSetVar #-}
makeLogger :: HasLogging a => a -> IO Logger
makeLogger app = makeYesodLogger
=<< globallyCache loggerSetVar (newLoggerSet defaultBufSize)
where
newLoggerSet = case getLogLocation app of
LogStdout -> newStdoutLoggerSet
LogStderr -> newStderrLoggerSet
LogFile f -> flip newFileLoggerSet f
Synopsis
- data GlobalCache a
- newGlobalCache :: IO (GlobalCache a)
- globallyCache :: GlobalCache a -> IO a -> IO a
- withGlobalCacheCleanup :: GlobalCache a -> IO b -> IO ()
Documentation
data GlobalCache a Source #
newGlobalCache :: IO (GlobalCache a) Source #
globallyCache :: GlobalCache a -> IO a -> IO a Source #
withGlobalCacheCleanup :: GlobalCache a -> IO b -> IO () Source #
Garbage collect one of our IORefs after an action has run
Global IORefs are problematic for ghci. ghci cannot garbage collect
them, so any state they hold will persist for an entire ghci session. This
causes a varietyof issues.
To avoid garbage collection issues, we can leverage a System.Mem.Weak to
add a finalizer. When that MVar gets garbage collected we can clear the
global IORef. This maintains the status quo, with minimal plumbing.