@@ -1,21 +1,40 @@
1−-- | A common problem is the desire to have an action run at a scheduled
2−-- interval, but only if it is needed. For example, instead of having
3−-- every web request result in a new @getCurrentTime@ call, we'd like to
4−-- have a single worker thread run every second, updating an @IORef@.
5−-- However, if the request frequency is less than once per second, this is
6−-- a pessimization, and worse, kills idle GC.
1+-- | In a multithreaded environment, running actions on a regularly scheduled
2+-- background thread can dramatically improve performance.
3+-- For example, web servers need to return the current time with each HTTP response.
4+-- For a high-volume server, it's much faster for a dedicated thread to run every
5+-- second, and write the current time to a shared 'IORef', than it is for each
6+-- request to make its own call to 'getCurrentTime'.
77--
8−-- This library allows you to define actions which will either be
9−-- performed by a dedicated thread or, in times of low volume, will be
10−-- executed by the calling thread.
8+-- But for a low-volume server, whose request frequency is less than once per
9+-- second, that approach will result in /more/ calls to 'getCurrentTime' than
10+-- necessary, and worse, kills idle GC.
11+--
12+-- This library solves that problem by allowing you to define actions which will
13+-- either be performed by a dedicated thread, or, in times of low volume, will
14+-- be executed by the calling thread.
15+--
16+-- Example usage:
17+--
18+-- @
19+-- import "Data.Time"
20+-- import "Control.AutoUpdate"
21+--
22+-- getTime <- 'mkAutoUpdate' 'defaultUpdateSettings'
23+-- { 'updateAction' = 'Data.Time.Clock.getCurrentTime'
24+-- , 'updateFreq' = 1000000 -- The default frequency, once per second
25+-- }
26+-- currentTime <- getTime
27+-- @
28+--
29+-- For more examples, <http://www.yesodweb.com/blog/2014/08/announcing-auto-update see the blog post introducing this library>.
1130module Control.AutoUpdate (
1231 -- * Type
1332 UpdateSettings
1433 , defaultUpdateSettings
1534 -- * Accessors
35+ , updateAction
1636 , updateFreq
1737 , updateSpawnThreshold
18− , updateAction
1938 -- * Creation
2039 , mkAutoUpdate
2140 ) where
@@ -27,9 +46,9 @@ import Control.Exception (SomeException, catch, throw, mask_, tr
2746import Control.Monad (void)
2847import Data.IORef (newIORef, readIORef, writeIORef)
2948
30−-- | Default value for creating an @UpdateSettings@.
49+-- | Default value for creating an 'UpdateSettings'.
3150--
32−-- Since 0.1.0
51+-- @since 0.1.0
3352defaultUpdateSettings :: UpdateSettings ()
3453defaultUpdateSettings = UpdateSettings
3554 { updateFreq = 1000000
@@ -39,44 +58,44 @@ defaultUpdateSettings = UpdateSettings
3958
4059-- | Settings to control how values are updated.
4160--
42−-- This should be constructed using @defaultUpdateSettings@ and record
61+-- This should be constructed using 'defaultUpdateSettings' and record
4362-- update syntax, e.g.:
4463--
4564-- @
46−-- let set = defaultUpdateSettings { updateAction = getCurrentTime }
65+-- let settings = 'defaultUpdateSettings' { 'updateAction' = 'Data.Time.Clock.getCurrentTime' }
4766-- @
4867--
49−-- Since 0.1.0
68+-- @since 0.1.0
5069data UpdateSettings a = UpdateSettings
5170 { updateFreq :: Int
5271 -- ^ Microseconds between update calls. Same considerations as
53− -- @threadDelay@ apply.
72+ -- 'threadDelay' apply.
5473 --
5574 -- Default: 1 second (1000000)
5675 --
57− -- Since 0.1.0
76+ -- @since 0.1.0
5877 , updateSpawnThreshold :: Int
5978 -- ^ NOTE: This value no longer has any effect, since worker threads are
6079 -- dedicated instead of spawned on demand.
6180 --
62− -- Previously, this determined: How many times the data must be requested
81+ -- Previously, this determined how many times the data must be requested
6382 -- before we decide to spawn a dedicated thread.
6483 --
6584 -- Default: 3
6685 --
67− -- Since 0.1.0
86+ -- @since 0.1.0
6887 , updateAction :: IO a
6988 -- ^ Action to be performed to get the current value.
7089 --
7190 -- Default: does nothing.
7291 --
73− -- Since 0.1.0
92+ -- @since 0.1.0
7493 }
7594
7695-- | Generate an action which will either read from an automatically
7796-- updated value, or run the update action in the current thread.
7897--
79−-- Since 0.1.0
98+-- @since 0.1.0
8099mkAutoUpdate :: UpdateSettings a -> IO (IO a)
81100mkAutoUpdate us = do
82101 -- A baton to tell the worker thread to generate a new value.
@@ -158,7 +177,7 @@ mkAutoUpdate us = do
158177 -- we have a current value, use it
159178 Right val -> return val
160179
161−-- | Turn a runtime exception into an impure exception, so that all @IO@
180+-- | Turn a runtime exception into an impure exception, so that all 'IO'
162181-- actions will complete successfully. This simply defers the exception until
163182-- the value is forced.
164183catchSome :: IO a -> IO a