freckle-app-1.8.1.0: Haskell application toolkit used at Freckle
Safe HaskellSafe-Inferred
LanguageHaskell2010

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

Documentation

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.