Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
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 IORef
s after an action has run
Global IORef
s 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.