timer-wheel-0.4.0: A timer wheel
Safe HaskellSafe-Inferred
LanguageHaskell2010

TimerWheel

Contents

Description

A simple, hashed timer wheel.

Synopsis

Timer wheel

data TimerWheel Source #

A timer wheel is a vector-of-collections-of timers to fire. It is configured with a spoke count and resolution. Timers may be scheduled arbitrarily far in the future. A timeout thread is spawned to step through the timer wheel and fire expired timers at regular intervals.

  • The spoke count determines the size of the timer vector.

    • A larger spoke count will result in less insert contention at each spoke and will require more memory to store the timer wheel.
    • A smaller spoke count will result in more insert contention at each spoke and will require less memory to store the timer wheel.
  • The resolution determines both the duration of time that each spoke corresponds to, and how often the timeout thread wakes. For example, with a resolution of 1s, a timer that expires at 2.5s will not fire until the timeout thread wakes at 3s.

    • A larger resolution will result in more insert contention at each spoke, less accurate timers, and will require fewer wakeups by the timeout thread.
    • A smaller resolution will result in less insert contention at each spoke, more accurate timers, and will require more wakeups by the timeout thread.
  • The timeout thread has some important properties:

    • There is only one, and it fires expired timers synchronously. If your timer actions execute quicky, register them directly. Otherwise, consider registering an action that enqueues the real action to be performed on a job queue.
    • Synchronous exceptions thrown by enqueued IO actions will bring the thread down, and the exception will be propagated to the thread that created the timer wheel. If you want to catch exceptions and log them, for example, you will have to bake this into the registered actions yourself.

As an example, below is a depiction of a timer wheel with 6 timers inserted across 8 spokes, and a resolution of .1s. It depicts a cursor at .3s, which indicates where the timeout thread currently is.

 0       .1      .2      .3      .4      .5      .6      .7
┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
│       │ A⁰    │       │ B¹ C⁰ │ D⁰    │       │       │ E² F⁰ │
└───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
                          ↑

After .1s, the timeout thread will advance to the next spoke and process all of the timers it passed over. In this case, C will fire, and B will be put back with its count decremented to 0. This is how the timer wheel can schedule a timer to fire arbitrarily far in the future: its count is simply the number of times its delay wraps the entire duration of the timer wheel.

 0       .1      .2      .3      .4      .5      .6      .7
┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
│       │ A⁰    │       │ B⁰    │ D⁰    │       │       │ E² F⁰ │
└───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
                                  ↑

create :: Scope -> Config -> IO TimerWheel Source #

Create a timer wheel in a scope.

Throws.

  • Calls error if the config is invalid

with :: Config -> (TimerWheel -> IO a) -> IO a Source #

Perform an action with a timer wheel.

Throws.

  • Calls error if the config is invalid
  • Throws the exception the given action throws, if any
  • Throws the exception the timer wheel thread throws, if any

data Config Source #

Timer wheel config.

  • spokes must be ∈ [1, maxBound]
  • resolution must ∈ (0, ∞]

Constructors

Config 

Fields

Instances

Instances details
Generic Config Source # 
Instance details

Defined in TimerWheel.Internal.Config

Associated Types

type Rep Config :: Type -> Type #

Methods

from :: Config -> Rep Config x #

to :: Rep Config x -> Config #

Show Config Source # 
Instance details

Defined in TimerWheel.Internal.Config

type Rep Config Source # 
Instance details

Defined in TimerWheel.Internal.Config

type Rep Config = D1 ('MetaData "Config" "TimerWheel.Internal.Config" "timer-wheel-0.4.0-FOBSLbc5FlnFiikIh3bi2O" 'False) (C1 ('MetaCons "Config" 'PrefixI 'True) (S1 ('MetaSel ('Just "spokes") 'SourceUnpack 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Just "resolution") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Fixed E6))))

register Source #

Arguments

:: TimerWheel 
-> Fixed E6

Delay, in seconds

-> IO ()

Action

-> IO (IO Bool) 

register wheel delay action registers an action action in timer wheel wheel to fire after delay seconds.

Returns an action that, when called, attempts to cancel the timer, and returns whether or not it was successful (False means the timer has already fired, or was already cancelled).

register_ Source #

Arguments

:: TimerWheel 
-> Fixed E6

Delay, in seconds

-> IO ()

Action

-> IO () 

Like register, but for when you don't intend to cancel the timer.

recurring Source #

Arguments

:: TimerWheel 
-> Fixed E6

Delay, in seconds

-> IO ()

Action

-> IO (IO ()) 

recurring wheel action delay registers an action action in timer wheel wheel to fire every delay seconds (or every resolution seconds, whichever is smaller).

Returns an action that, when called, cancels the recurring timer.

recurring_ Source #

Arguments

:: TimerWheel 
-> Fixed E6

Delay, in seconds

-> IO ()

Action

-> IO () 

Like recurring, but for when you don't intend to cancel the timer.