Safe HaskellNone



Implementation of configuration reader with watching support.



type ConfigReader = IO (Result ConfigData) Source #

A type for functions that can return the configuration when executed.

data ReloadModel Source #

Reload model data type.



We are using notifications

ReloadPoll Int

We are using polling

data ServerState Source #

Server state data type.




maxIdlePollRounds :: Int Source #

Maximum no-reload poll rounds before reverting to inotify.

watchInterval :: Int Source #

Reload timeout in microseconds.

pollInterval :: Int Source #

Ratelimit timeout in microseconds.

reloadRatelimit :: Integer Source #

Ratelimit timeout in microseconds, as an Integer.

initialPoll :: ReloadModel Source #

Initial poll round.

data ConfigReload Source #

Reload status data type.



No need to reload


Configuration reloaded


Error during configuration reload

Configuration handling

Helper functions

moveToPolling :: String -> INotify -> FilePath -> (Result ConfigData -> IO ()) -> MVar ServerState -> IO ReloadModel Source #

Helper function for logging transition into polling mode.

moveToNotify :: IO ReloadModel Source #

Helper function for logging transition into inotify mode.

Configuration loading

updateConfig :: FilePath -> (Result ConfigData -> IO ()) -> IO () Source #

(Re)loads the configuration.

safeUpdateConfig :: FilePath -> FStat -> (Result ConfigData -> IO ()) -> IO (FStat, ConfigReload) Source #

Wrapper over updateConfig that handles IO errors.

Watcher threads

We have three threads/functions that can mutate the server state:

  1. the long-interval watcher (onWatcherTimer)
  2. the polling watcher (onPollTimer)
  3. the inotify event handler (onInotify)

All of these will mutate the server state under modifyMVar or modifyMVar_, so that server transitions are more or less atomic. The inotify handler remains active during polling mode, but checks for polling mode and doesn't do anything in this case (this check is needed even if we would unregister the event handler due to how events are serialised).

onWatcherTimer :: FilePath -> (Result ConfigData -> IO ()) -> MVar ServerState -> IO () Source #

Long-interval reload watcher.

This is on top of the inotify-based triggered reload.

onWatcherInner :: FilePath -> (Result ConfigData -> IO ()) -> ServerState -> IO ServerState Source #

Inner onWatcher handler.

This mutates the server state under a modifyMVar_ call. It never changes the reload model, just does a safety reload and tried to re-establish the inotify watcher.

onPollTimer :: IO Bool -> FilePath -> (Result ConfigData -> IO ()) -> MVar ServerState -> IO () Source #

Short-interval (polling) reload watcher.

This is only active when we're in polling mode; it will automatically exit when it detects that the state has changed to notification.

onPollInner :: IO Bool -> FilePath -> (Result ConfigData -> IO ()) -> ServerState -> IO (ServerState, Bool) Source #

Inner onPoll handler.

This again mutates the state under a modifyMVar call, and also returns whether the thread should continue or not.

addNotifier :: INotify -> FilePath -> (Result ConfigData -> IO ()) -> MVar ServerState -> IO Bool Source #

Setup inotify watcher.

This tries to setup the watch descriptor; in case of any IO errors, it will return False.

onInotify :: INotify -> String -> (Result ConfigData -> IO ()) -> MVar ServerState -> Event -> IO () Source #

Inotify event handler.

initConfigReader :: (Result ConfigData -> IO ()) -> IO () Source #