on master help sign in
Improve auto-update docs
346e5e7Maximilian Tagher
auto-update/Control/AutoUpdate.hs+34−22
@@ -1,21 +1,33 @@
1−-- | A common problem is the desire to have an action run at a scheduled
1+-- | In a multithreaded environment, running actions on a regularly scheduled background thread can dramatically improve performance.
2−-- interval, but only if it is needed. For example, instead of having
2+-- For example, web servers need to return the current time with each HTTP response.
3−-- every web request result in a new @getCurrentTime@ call, we'd like to
3+-- For a high-volume server, it's much faster for a dedicated thread to run every second, and write the current time to a shared 'IORef', than it is for each request to make its own call to 'getCurrentTime'.
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.
7--
4--
8−-- This library allows you to define actions which will either be
5+-- But for a low-volume server, whose request frequency is less than once per second, that approach will result in /more/ calls to 'getCurrentTime' than necessary, and worse, kills idle GC.
6+--
9−-- performed by a dedicated thread or, in times of low volume, will be
7+-- This library solves that problem by allowing you to define actions which will either be performed by a dedicated thread, or, in times of low volume, will be executed by the calling thread.
10−-- executed by the calling thread.
8+--
9+-- Example usage:
10+--
11+-- @
12+-- import "Data.Time"
13+-- import "Control.AutoUpdate"
14+--
15+-- getTime <- 'mkAutoUpdate' 'defaultUpdateSettings'
16+-- { 'updateAction' = 'Data.Time.Clock.getCurrentTime'
17+-- , 'updateFreq' = 1000000 -- The default frequency, once per second
18+-- }
19+-- currentTime <- getTime
20+-- @
21+--
22+-- For more examples, <http://www.yesodweb.com/blog/2014/08/announcing-auto-update see the blog post introducing this library>.
11module Control.AutoUpdate (
23module Control.AutoUpdate (
12 -- * Type
24 -- * Type
13 UpdateSettings
25 UpdateSettings
14 , defaultUpdateSettings
26 , defaultUpdateSettings
15 -- * Accessors
27 -- * Accessors
28+ , updateAction
16 , updateFreq
29 , updateFreq
17 , updateSpawnThreshold
30 , updateSpawnThreshold
18− , updateAction
19 -- * Creation
31 -- * Creation
20 , mkAutoUpdate
32 , mkAutoUpdate
21 ) where
33 ) where
@@ -27,9 +39,9 @@ import Control.Exception (SomeException, catch, throw, mask_, tr
27import Control.Monad (void)
39import Control.Monad (void)
28import Data.IORef (newIORef, readIORef, writeIORef)
40import Data.IORef (newIORef, readIORef, writeIORef)
29
41
30−-- | Default value for creating an @UpdateSettings@.
42+-- | Default value for creating an 'UpdateSettings'.
31--
43--
32−-- Since 0.1.0
44+-- @since 0.1.0
33defaultUpdateSettings :: UpdateSettings ()
45defaultUpdateSettings :: UpdateSettings ()
34defaultUpdateSettings = UpdateSettings
46defaultUpdateSettings = UpdateSettings
35 { updateFreq = 1000000
47 { updateFreq = 1000000
@@ -39,44 +51,44 @@ defaultUpdateSettings = UpdateSettings
39
51
40-- | Settings to control how values are updated.
52-- | Settings to control how values are updated.
41--
53--
42−-- This should be constructed using @defaultUpdateSettings@ and record
54+-- This should be constructed using 'defaultUpdateSettings' and record
43-- update syntax, e.g.:
55-- update syntax, e.g.:
44--
56--
45-- @
57-- @
46−-- let set = defaultUpdateSettings { updateAction = getCurrentTime }
58+-- let settings = 'defaultUpdateSettings' { 'updateAction' = 'Data.Time.Clock.getCurrentTime' }
47-- @
59-- @
48--
60--
49−-- Since 0.1.0
61+-- @since 0.1.0
50data UpdateSettings a = UpdateSettings
62data UpdateSettings a = UpdateSettings
51 { updateFreq :: Int
63 { updateFreq :: Int
52 -- ^ Microseconds between update calls. Same considerations as
64 -- ^ Microseconds between update calls. Same considerations as
53− -- @threadDelay@ apply.
65+ -- 'threadDelay' apply.
54 --
66 --
55 -- Default: 1 second (1000000)
67 -- Default: 1 second (1000000)
56 --
68 --
57− -- Since 0.1.0
69+ -- @since 0.1.0
58 , updateSpawnThreshold :: Int
70 , updateSpawnThreshold :: Int
59 -- ^ NOTE: This value no longer has any effect, since worker threads are
71 -- ^ NOTE: This value no longer has any effect, since worker threads are
60 -- dedicated instead of spawned on demand.
72 -- dedicated instead of spawned on demand.
61 --
73 --
62− -- Previously, this determined: How many times the data must be requested
74+ -- Previously, this determined how many times the data must be requested
63 -- before we decide to spawn a dedicated thread.
75 -- before we decide to spawn a dedicated thread.
64 --
76 --
65 -- Default: 3
77 -- Default: 3
66 --
78 --
67− -- Since 0.1.0
79+ -- @since 0.1.0
68 , updateAction :: IO a
80 , updateAction :: IO a
69 -- ^ Action to be performed to get the current value.
81 -- ^ Action to be performed to get the current value.
70 --
82 --
71 -- Default: does nothing.
83 -- Default: does nothing.
72 --
84 --
73− -- Since 0.1.0
85+ -- @since 0.1.0
74 }
86 }
75
87
76-- | Generate an action which will either read from an automatically
88-- | Generate an action which will either read from an automatically
77-- updated value, or run the update action in the current thread.
89-- updated value, or run the update action in the current thread.
78--
90--
79−-- Since 0.1.0
91+-- @since 0.1.0
80mkAutoUpdate :: UpdateSettings a -> IO (IO a)
92mkAutoUpdate :: UpdateSettings a -> IO (IO a)
81mkAutoUpdate us = do
93mkAutoUpdate us = do
82 -- A baton to tell the worker thread to generate a new value.
94 -- A baton to tell the worker thread to generate a new value.
@@ -158,7 +170,7 @@ mkAutoUpdate us = do
158 -- we have a current value, use it
170 -- we have a current value, use it
159 Right val -> return val
171 Right val -> return val
160
172
161−-- | Turn a runtime exception into an impure exception, so that all @IO@
173+-- | Turn a runtime exception into an impure exception, so that all 'IO'
162-- actions will complete successfully. This simply defers the exception until
174-- actions will complete successfully. This simply defers the exception until
163-- the value is forced.
175-- the value is forced.
164catchSome :: IO a -> IO a
176catchSome :: IO a -> IO a
auto-update/Control/Debounce.hs+27−11
@@ -3,10 +3,26 @@
3-- period of time.
3-- period of time.
4--
4--
5-- This is useful as an optimization, for example to ensure that logs are only
5-- 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
6+-- flushed to disk at most once per second.
7−-- example usage.
8--
7--
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
10module Control.Debounce
26module Control.Debounce
11 ( -- * Type
27 ( -- * Type
12 DebounceSettings
28 DebounceSettings
@@ -25,14 +41,14 @@ import Control.Monad (forever, void)
25
41
26-- | Settings to control how debouncing should work.
42-- | Settings to control how debouncing should work.
27--
43--
28−-- This should be constructed using @defaultDebounceSettings@ and record
44+-- This should be constructed using 'defaultDebounceSettings' and record
29-- update syntax, e.g.:
45-- update syntax, e.g.:
30--
46--
31-- @
47-- @
32−-- let set = defaultDebounceSettings { debounceAction = flushLog }
48+-- let settings = 'defaultDebounceSettings' { 'debounceAction' = flushLog }
33-- @
49-- @
34--
50--
35−-- Since 0.1.2
51+-- @since 0.1.2
36data DebounceSettings = DebounceSettings
52data DebounceSettings = DebounceSettings
37 { debounceFreq :: Int
53 { debounceFreq :: Int
38 -- ^ Microseconds lag required between subsequence calls to the debounced
54 -- ^ Microseconds lag required between subsequence calls to the debounced
@@ -40,7 +56,7 @@ data DebounceSettings = DebounceSettings
40 --
56 --
41 -- Default: 1 second (1000000)
57 -- Default: 1 second (1000000)
42 --
58 --
43− -- Since 0.1.2
59+ -- @since 0.1.2
44 , debounceAction :: IO ()
60 , debounceAction :: IO ()
45 -- ^ Action to be performed.
61 -- ^ Action to be performed.
46 --
62 --
@@ -48,12 +64,12 @@ data DebounceSettings = DebounceSettings
48 --
64 --
49 -- Default: does nothing.
65 -- Default: does nothing.
50 --
66 --
51− -- Since 0.1.2
67+ -- @since 0.1.2
52 }
68 }
53
69
54−-- | Default value for creating a @DebounceSettings@.
70+-- | Default value for creating a 'DebounceSettings'.
55--
71--
56−-- Since 0.1.2
72+-- @since 0.1.2
57defaultDebounceSettings :: DebounceSettings
73defaultDebounceSettings :: DebounceSettings
58defaultDebounceSettings = DebounceSettings
74defaultDebounceSettings = DebounceSettings
59 { debounceFreq = 1000000
75 { debounceFreq = 1000000
@@ -64,7 +80,7 @@ defaultDebounceSettings = DebounceSettings
64-- performed. The action will either be performed immediately, or after the
80-- performed. The action will either be performed immediately, or after the
65-- current cooldown period has expired.
81-- current cooldown period has expired.
66--
82--
67−-- Since 0.1.2
83+-- @since 0.1.2
68mkDebounce :: DebounceSettings -> IO (IO ())
84mkDebounce :: DebounceSettings -> IO (IO ())
69mkDebounce (DebounceSettings freq action) = do
85mkDebounce (DebounceSettings freq action) = do
70 baton <- newEmptyMVar
86 baton <- newEmptyMVar