on master help sign in
Merge pull request #542 from yesodweb/autoupdateDocs

Minor improvements to auto-update docs

commitcf2ff48f60554b2326ff2d9979e9effdc583b6ba authorMichael Snoyman <michael@snoyman.com> dateSun 24 Apr 2016, 08:54 (10 years ago) parent5dc1cc595e3805
2 files changed+68−33
auto-update/Control/AutoUpdate.hs+41−22 auto-update/Control/Debounce.hs+27−11
auto-update/Control/AutoUpdate.hs+41−22
@@ -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
auto-update/Control/Debounce.hs+27−11
@@ -3,10 +3,26 @@
33-- period of time.
44--
55-- This is useful as an optimization, for example to ensure that logs are only
6−-- flushed to disk at most once per second. See the fast-logger package for an
7−-- example usage.
6+-- flushed to disk at most once per second.
87--
9−-- Since 0.1.2
8+-- Example usage:
9+--
10+-- @
11+-- printString <- 'mkDebounce' 'defaultDebounceSettings'
12+-- { 'debounceAction' = putStrLn "Running action"
13+-- , 'debounceFreq' = 5000000 -- 5 seconds
14+-- }
15+-- @
16+--
17+-- >>> printString
18+-- Running action
19+-- >>> printString
20+-- <Wait five seconds>
21+-- Running action
22+--
23+-- See the fast-logger package ("System.Log.FastLogger") for real-world usage.
24+--
25+-- @since 0.1.2
1026module Control.Debounce
1127 ( -- * Type
1228 DebounceSettings
@@ -25,14 +41,14 @@ import Control.Monad (forever, void)
2541
2642-- | Settings to control how debouncing should work.
2743--
28−-- This should be constructed using @defaultDebounceSettings@ and record
44+-- This should be constructed using 'defaultDebounceSettings' and record
2945-- update syntax, e.g.:
3046--
3147-- @
32−-- let set = defaultDebounceSettings { debounceAction = flushLog }
48+-- let settings = 'defaultDebounceSettings' { 'debounceAction' = flushLog }
3349-- @
3450--
35−-- Since 0.1.2
51+-- @since 0.1.2
3652data DebounceSettings = DebounceSettings
3753 { debounceFreq :: Int
3854 -- ^ Microseconds lag required between subsequence calls to the debounced
@@ -40,7 +56,7 @@ data DebounceSettings = DebounceSettings
4056 --
4157 -- Default: 1 second (1000000)
4258 --
43− -- Since 0.1.2
59+ -- @since 0.1.2
4460 , debounceAction :: IO ()
4561 -- ^ Action to be performed.
4662 --
@@ -48,12 +64,12 @@ data DebounceSettings = DebounceSettings
4864 --
4965 -- Default: does nothing.
5066 --
51− -- Since 0.1.2
67+ -- @since 0.1.2
5268 }
5369
54−-- | Default value for creating a @DebounceSettings@.
70+-- | Default value for creating a 'DebounceSettings'.
5571--
56−-- Since 0.1.2
72+-- @since 0.1.2
5773defaultDebounceSettings :: DebounceSettings
5874defaultDebounceSettings = DebounceSettings
5975 { debounceFreq = 1000000
@@ -64,7 +80,7 @@ defaultDebounceSettings = DebounceSettings
6480-- performed. The action will either be performed immediately, or after the
6581-- current cooldown period has expired.
6682--
67−-- Since 0.1.2
83+-- @since 0.1.2
6884mkDebounce :: DebounceSettings -> IO (IO ())
6985mkDebounce (DebounceSettings freq action) = do
7086 baton <- newEmptyMVar