-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A simplified implementation of Erlang/OTP like supervisor over thread -- -- Please see the README on Github at -- https://github.com/nshimaza/thread-supervisor#readme @package thread-supervisor @version 0.2.0.0 -- | Queue with delay before elements become available to dequeue. -- -- DelayedQueue is a FIFO but it does NOT make element available -- to pop immediately after the element was pushed. DelayedQueue looks -- like empty until its delay-buffer is filled up by pushed elements. -- When a value is pushed to a DelayedQueue where delay-buffer of the -- queue is already full-filled, the oldest element becomes available to -- dequeue. -- -- Entire elements within DelayedQueue are always inlined in enqueued -- order. Only older elements overflowed from delay-buffer are available -- to dequeue. If delay-buffer is not yet filled, no element is available -- to dequeue. Once delay-buffer is filled, delay-buffer always keeps -- given number of newest elements. module Data.DelayedQueue -- | Queue with delay before elements become available to dequeue. data DelayedQueue a -- | Create a new DelayedQueue with given delay. newEmptyDelayedQueue :: Int -> DelayedQueue a -- | Enqueue a value to a DelayedQueue. push :: a -> DelayedQueue a -> DelayedQueue a -- | Dequeue a value from a DelayedQueue. pop :: DelayedQueue a -> Maybe (a, DelayedQueue a) instance GHC.Show.Show a => GHC.Show.Show (Data.DelayedQueue.DelayedQueue a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.DelayedQueue.DelayedQueue a) -- | A simplified implementation of Erlang/OTP like supervisor over thread. -- This is internal module where all real implementations present. module Control.Concurrent.SupervisorInternal -- | Message queue abstraction. data Inbox a Inbox :: TQueue a -> TVar Word -> TVar [a] -> Word -> Inbox a -- | Concurrent queue receiving message from other threads. [inboxQueue] :: Inbox a -> TQueue a -- | Number of elements currently held by the Inbox. [inboxLength] :: Inbox a -> TVar Word -- | Saved massage by receiveSelect. It keeps messages not selected -- by receiveSelect in reversed order. Latest message is kept at head of -- the list. [inboxSaveStack] :: Inbox a -> TVar [a] -- | Maximum length of the Inbox. [inboxMaxBound] :: Inbox a -> Word -- | Maximum length of Inbox. newtype InboxLength InboxLength :: Word -> InboxLength -- | Write end of Inbox exposed to outside of actor. newtype ActorQ a ActorQ :: Inbox a -> ActorQ a -- | Create a new empty Inbox. newInbox :: InboxLength -> IO (Inbox a) -- | Send a message to given ActorQ. Block while the queue is full. send :: ActorQ a -> a -> IO () -- | Send a message to sending actor itself. Block while the queue is full. sendToMe :: Inbox a -> a -> IO () -- | Try to send a message to given ActorQ. Return Nothing if the -- queue is already full. trySend :: ActorQ a -> a -> IO (Maybe ()) -- | Try to end a message to sending actor itself. Return Nothing if the -- queue is already full. trySendToMe :: Inbox a -> a -> IO (Maybe ()) -- | Number of elements currently held by the ActorQ. length :: ActorQ a -> IO Word -- | Perform selective receive from given Inbox. -- -- receiveSelect searches given queue for first interesting -- message predicated by user supplied function. It applies the predicate -- to the queue, returns the first element that satisfy the predicate, -- and remove the element from the Inbox. -- -- It blocks until interesting message arrived if no interesting message -- was found in the queue. -- -- Caution -- -- Use this function with care. It does NOT discard any message -- unsatisfying predicate. It keeps them in the queue for future receive -- and the function itself blocks until interesting message arrived. That -- causes your queue filled up by non-interesting messages. There is no -- escape hatch. -- -- Consider using tryReceiveSelect instead. -- -- Caveat -- -- Current implementation has performance caveat. It has O(n) -- performance characteristic where n is number of messages -- existing before your interested message appears. It is because this -- function performs liner scan from the top of the queue every time it -- is called. It doesn't cache pair of predicates and results you have -- given before. -- -- Use this function in limited situation only. receiveSelect :: (a -> Bool) -> Inbox a -> IO a -- | Try to perform selective receive from given Inbox. -- -- tryReceiveSelect searches given queue for first interesting -- message predicated by user supplied function. It applies the predicate -- to the queue, returns the first element that satisfy the predicate, -- and remove the element from the Inbox. -- -- It return Nothing if there is no interesting message found in the -- queue. -- -- Caveat -- -- Current implementation has performance caveat. It has O(n) -- performance characteristic where n is number of messages -- existing before your interested message appears. It is because this -- function performs liner scan from the top of the queue every time it -- is called. It doesn't cache pair of predicates and results you have -- given before. -- -- Use this function in limited situation only. tryReceiveSelect :: (a -> Bool) -> Inbox a -> IO (Maybe a) -- | Find oldest message satisfying predicate from saveStack, -- return the message, and remove it from the saveStack. Returns -- Nothing if there is no satisfying message. pickFromSaveStack :: (a -> Bool) -> [a] -> Maybe (a, [a]) -- | Update Inbox with new saveStack which already have one -- message removed. oneMessageRemoved :: TVar Word -> TVar [a] -> [a] -> STM () -- | Receive first message in Inbox. Block until message available. receive :: Inbox a -> IO a -- | Try to receive first message in Inbox. It returns Nothing if -- there is no message available. tryReceive :: Inbox a -> IO (Maybe a) -- | Type synonym of user supplied message handler working inside actor. type ActorHandler message result = (Inbox message -> IO result) -- | Actor representation. data Actor message result Actor :: ActorQ message -> IO result -> Actor message result -- | Write end of message queue of Actor [actorQueue] :: Actor message result -> ActorQ message -- | IO action to execute Actor [actorAction] :: Actor message result -> IO result -- | Create a new actor. -- -- Users have to supply a message handler function with -- ActorHandler type. ActorHandler accepts a Inbox and -- returns anything. -- -- newActor creates a new Inbox, apply user supplied -- message handler to the queue, returns reference to write-end of the -- queue and IO action of the actor. Because newActor only returns -- ActorQ, caller of newActor can only send messages to -- created actor. Caller cannot receive message from the queue. -- -- Inbox, or read-end of the queue, is passed to user supplied -- message handler so the handler can receive message to the actor. If -- the handler need to send a message to itself, wrap the message queue -- by ActorQ constructor then use send over created -- ActorQ. Here is an example. -- --
-- send (ActorQ yourInbox) message --newActor :: ActorHandler message result -> IO (Actor message result) -- | Create a new actor with bounded inbox queue. newBoundedActor :: InboxLength -> ActorHandler message result -> IO (Actor message result) -- | Create a new finite state machine. -- -- The state machine waits for new message at Inbox then callback -- user supplied message handler. The message handler must return -- Right with new state or Left with final result. When -- Right is returned, the state machine waits for next message. -- When Left is returned, the state machine terminates and returns -- the result. -- -- newStateMachine returns an IO action wrapping the state machine -- described above. The returned IO action can be executed within an -- Async or bare thread. -- -- Created IO action is designed to run in separate thread from main -- thread. If you try to run the IO action at main thread without having -- producer of the message queue you gave, the state machine will dead -- lock. newStateMachine :: state -> (state -> message -> IO (Either result state)) -> ActorHandler message result -- | create an unbound actor of newStateMachine. Short-cut of following. -- --
-- newActor $ newStateMachine initialState messageHandler --newStateMachineActor :: state -> (state -> message -> IO (Either result state)) -> IO (Actor message result) -- | Type synonym of callback function to obtain return value. type ServerCallback a = (a -> IO ()) -- | Send an asynchronous request to a server. cast :: ActorQ cmd -> cmd -> IO () -- | Timeout of call method for server behavior in microseconds. Default is -- 5 second. newtype CallTimeout CallTimeout :: Int -> CallTimeout -- | Send an synchronous request to a server and waits for a return value -- until timeout. call :: CallTimeout -> ActorQ cmd -> (ServerCallback a -> cmd) -> IO (Maybe a) -- | Make an asynchronous call to a server and give result in CPS style. -- The return value is delivered to given callback function. It also can -- fail by timeout. Calling thread can wait for a return value -- from the callback. -- -- Use this function with care because there is no guaranteed -- cancellation of background worker thread other than timeout. Giving -- infinite timeout (zero) to the CallTimeout argument may cause -- the background thread left to run, possibly indefinitely. callAsync :: CallTimeout -> ActorQ cmd -> (ServerCallback a -> cmd) -> (Maybe a -> IO b) -> IO (Async b) -- | Send an request to a server but ignore return value. callIgnore :: ActorQ cmd -> (ServerCallback a -> cmd) -> IO () -- | ExitReason indicates reason of thread termination. data ExitReason -- | Thread was normally finished. Normal :: ExitReason -- | A synchronous exception was thrown and it was not caught. This -- indicates some unhandled error happened inside of the thread handler. UncaughtException :: SomeException -> ExitReason -- | An asynchronous exception was thrown. This also happen when the thread -- was killed by supervisor. Killed :: ExitReason -- | Monitor is user supplied callback function which is called when -- monitored thread is terminated. type Monitor = ExitReason " Reason of thread termination." -> ThreadId " ID of terminated thread." -> IO () -- | MonitoredAction is type synonym of function with callback on -- termination installed. Its type signature fits to argument for -- forkIOWithUnmask. type MonitoredAction = (IO () -> IO ()) -> IO () -- | Install Monitor callback function to simple IO action. watch :: Monitor -> IO () -> MonitoredAction -- | Convert simple IO action to MonitoredAction without installing -- Monitor. noWatch :: IO () -> MonitoredAction -- | Install another Monitor callback function to -- MonitoredAction. nestWatch :: Monitor -> MonitoredAction -> MonitoredAction -- | Restart defines when terminated child thread triggers restart -- operation by its supervisor. Restart only defines when it -- triggers restart operation. It does not directly means if the thread -- will be or will not be restarted. It is determined by restart strategy -- of supervisor. For example, a static Temporary child never -- triggers restart on its termination but static Temporary child -- will be restarted if another Permanent or Transient -- thread with common supervisor triggered restart operation and the -- supervisor has OneForAll strategy. data Restart -- | Permanent thread always triggers restart. Permanent :: Restart -- | Transient thread triggers restart only if it was terminated by -- exception. Transient :: Restart -- | Temporary thread never triggers restart. Temporary :: Restart -- | ChildSpec is representation of IO action which can be -- supervised by supervisor. Supervisor can run the IO action with -- separate thread, watch its termination and restart it based on restart -- type. data ChildSpec ChildSpec :: Restart -> MonitoredAction -> ChildSpec -- | Create a ChildSpec from MonitoredAction. newMonitoredChildSpec :: Restart -> MonitoredAction -> ChildSpec -- | Create a ChildSpec from plain IO action. newChildSpec :: Restart -> IO () -> ChildSpec -- | Add a Monitor function to existing ChildSpec. addMonitor :: Monitor -> ChildSpec -> ChildSpec -- | ThreadMap is mutable variable which holds pool of living -- threads and ChildSpec of each thread. ThreadMap is used inside -- of supervisor only. type ThreadMap = IORef (Map ThreadId ChildSpec) -- | Create an empty ThreadMap newThreadMap :: IO ThreadMap -- | Start new thread based on given ChildSpec, register the thread -- to given ThreadMap then returns ThreadId of the thread. newThread :: ThreadMap -> ChildSpec -> IO ThreadId -- | RestartSensitivity defines condition how supervisor determines -- intensive restart is happening. If more than -- restartSensitivityIntensity time of restart is triggered within -- restartSensitivityPeriod, supervisor decides intensive restart -- is happening and it terminates itself. Default intensity (maximum -- number of acceptable restart) is 1. Default period is 5 seconds. data RestartSensitivity RestartSensitivity :: Int -> TimeSpec -> RestartSensitivity -- | Maximum number of restart accepted within the period below. [restartSensitivityIntensity] :: RestartSensitivity -> Int -- | Length of time window in TimeSpec where the number of restarts -- is counted. [restartSensitivityPeriod] :: RestartSensitivity -> TimeSpec -- | IntenseRestartDetector keeps data used for detecting intense -- restart. It keeps maxR (maximum restart intensity), maxT (period of -- majoring restart intensity) and history of restart with system -- timestamp in Monotonic form. data IntenseRestartDetector IntenseRestartDetector :: TimeSpec -> DelayedQueue TimeSpec -> IntenseRestartDetector -- | Length of time window in TimeSpec where the number of restarts -- is counted. [intenseRestartDetectorPeriod] :: IntenseRestartDetector -> TimeSpec -- | Restart timestamp history. [intenseRestartDetectorHistory] :: IntenseRestartDetector -> DelayedQueue TimeSpec -- | Create new IntenseRestartDetector with given RestartSensitivity -- parameters. newIntenseRestartDetector :: RestartSensitivity -> IntenseRestartDetector -- | Determine if the last restart results intensive restart. It pushes the -- last restart timestamp to the DelayedQueue of restart history -- held inside of the IntenseRestartDetector then check if the oldest -- restart record is pushed out from the queue. If no record was pushed -- out, there are less number of restarts than limit, so it is not -- intensive. If a record was pushed out, it means we had one more -- restarts than allowed. If the oldest restart and newest restart -- happened within allowed time interval, it is intensive. -- -- This function implements pure part of detectIntenseRestartNow. detectIntenseRestart :: IntenseRestartDetector -> TimeSpec -> (Bool, IntenseRestartDetector) -- | Get current system timestamp in Monotonic form. getCurrentTime :: IO TimeSpec -- | Determine if intensive restart is happening now. It is called when -- restart is triggered by some thread termination. detectIntenseRestartNow :: IntenseRestartDetector -> IO (Bool, IntenseRestartDetector) -- | SupervisorMessage defines all message types supervisor can -- receive. data SupervisorMessage -- | Notification of child thread termination. Down :: ExitReason -> ThreadId -> SupervisorMessage -- | Command to start a new supervised thread. StartChild :: ChildSpec -> ServerCallback ThreadId -> SupervisorMessage -- | Type synonym for write-end of supervisor's message queue. type SupervisorQueue = ActorQ SupervisorMessage -- | Type synonym for read-end of supervisor's message queue. type SupervisorInbox = Inbox SupervisorMessage -- | Start a new thread with supervision. newSupervisedThread :: SupervisorQueue -> ThreadMap -> ChildSpec -> IO ThreadId -- | Start all given ChildSpec on new thread each with supervision. startAllSupervisedThread :: SupervisorQueue -> ThreadMap -> [ChildSpec] -> IO () -- | Kill all running threads supervised by the supervisor represented by -- SupervisorQueue. killAllSupervisedThread :: SupervisorInbox -> ThreadMap -> IO () -- | Restart strategy of supervisor data Strategy -- | Restart only exited thread. OneForOne :: Strategy -- | Restart all threads supervised by the same supervisor of exited -- thread. OneForAll :: Strategy -- | Create a supervisor with OneForOne restart strategy and has no -- static ChildSpec. When it started, it has no child threads. -- Only newChild can add new thread supervised by the supervisor. -- Thus the simple one-for-one supervisor only manages dynamic and -- Temporary children. newSimpleOneForOneSupervisor :: ActorHandler SupervisorMessage () -- | Create a supervisor. -- -- When created supervisor IO action started, it automatically creates -- child threads based on given ChildSpec list and supervise them. -- After it created such static children, it listens given -- SupervisorQueue. User can let the supervisor creates dynamic -- child thread by calling newChild. Dynamic child threads created -- by newChild are also supervised. -- -- When the supervisor thread is killed or terminated in some reason, all -- children including static children and dynamic children are all -- killed. -- -- With OneForOne restart strategy, when a child thread -- terminated, it is restarted based on its restart type given in -- ChildSpec. If the terminated thread has Permanent -- restart type, supervisor restarts it regardless its exit reason. If -- the terminated thread has Transient restart type, and -- termination reason is other than Normal (meaning -- UncaughtException or Killed), it is restarted. If the -- terminated thread has Temporary restart type, supervisor does -- not restart it regardless its exit reason. -- -- Created IO action is designed to run in separate thread from main -- thread. If you try to run the IO action at main thread without having -- producer of the supervisor queue you gave, the supervisor will dead -- lock. newSupervisor :: Strategy -> RestartSensitivity -> [ChildSpec] -> ActorHandler SupervisorMessage () -- | Ask the supervisor to spawn new temporary child thread. Returns -- ThreadId of the new child. newChild :: CallTimeout -> SupervisorQueue -> ChildSpec -> IO (Maybe ThreadId) instance GHC.Show.Show Control.Concurrent.SupervisorInternal.Restart instance GHC.Classes.Eq Control.Concurrent.SupervisorInternal.Restart instance GHC.Show.Show Control.Concurrent.SupervisorInternal.ExitReason instance Data.Default.Class.Default Control.Concurrent.SupervisorInternal.RestartSensitivity instance Data.Default.Class.Default Control.Concurrent.SupervisorInternal.CallTimeout instance Data.Default.Class.Default Control.Concurrent.SupervisorInternal.InboxLength -- | A simplified implementation of Erlang/OTP like supervisor over thread -- and underlying behaviors. module Control.Concurrent.Supervisor -- | Message queue abstraction. data Inbox a -- | Write end of Inbox exposed to outside of actor. data ActorQ a -- | Send a message to given ActorQ. Block while the queue is full. send :: ActorQ a -> a -> IO () -- | Send a message to sending actor itself. Block while the queue is full. sendToMe :: Inbox a -> a -> IO () -- | Try to send a message to given ActorQ. Return Nothing if the -- queue is already full. trySend :: ActorQ a -> a -> IO (Maybe ()) -- | Try to end a message to sending actor itself. Return Nothing if the -- queue is already full. trySendToMe :: Inbox a -> a -> IO (Maybe ()) -- | Number of elements currently held by the ActorQ. length :: ActorQ a -> IO Word -- | Receive first message in Inbox. Block until message available. receive :: Inbox a -> IO a -- | Try to receive first message in Inbox. It returns Nothing if -- there is no message available. tryReceive :: Inbox a -> IO (Maybe a) -- | Perform selective receive from given Inbox. -- -- receiveSelect searches given queue for first interesting -- message predicated by user supplied function. It applies the predicate -- to the queue, returns the first element that satisfy the predicate, -- and remove the element from the Inbox. -- -- It blocks until interesting message arrived if no interesting message -- was found in the queue. -- -- Caution -- -- Use this function with care. It does NOT discard any message -- unsatisfying predicate. It keeps them in the queue for future receive -- and the function itself blocks until interesting message arrived. That -- causes your queue filled up by non-interesting messages. There is no -- escape hatch. -- -- Consider using tryReceiveSelect instead. -- -- Caveat -- -- Current implementation has performance caveat. It has O(n) -- performance characteristic where n is number of messages -- existing before your interested message appears. It is because this -- function performs liner scan from the top of the queue every time it -- is called. It doesn't cache pair of predicates and results you have -- given before. -- -- Use this function in limited situation only. receiveSelect :: (a -> Bool) -> Inbox a -> IO a -- | Try to perform selective receive from given Inbox. -- -- tryReceiveSelect searches given queue for first interesting -- message predicated by user supplied function. It applies the predicate -- to the queue, returns the first element that satisfy the predicate, -- and remove the element from the Inbox. -- -- It return Nothing if there is no interesting message found in the -- queue. -- -- Caveat -- -- Current implementation has performance caveat. It has O(n) -- performance characteristic where n is number of messages -- existing before your interested message appears. It is because this -- function performs liner scan from the top of the queue every time it -- is called. It doesn't cache pair of predicates and results you have -- given before. -- -- Use this function in limited situation only. tryReceiveSelect :: (a -> Bool) -> Inbox a -> IO (Maybe a) -- | Type synonym of user supplied message handler working inside actor. type ActorHandler message result = (Inbox message -> IO result) -- | Actor representation. data Actor message result Actor :: ActorQ message -> IO result -> Actor message result -- | Write end of message queue of Actor [actorQueue] :: Actor message result -> ActorQ message -- | IO action to execute Actor [actorAction] :: Actor message result -> IO result -- | Create a new actor. -- -- Users have to supply a message handler function with -- ActorHandler type. ActorHandler accepts a Inbox and -- returns anything. -- -- newActor creates a new Inbox, apply user supplied -- message handler to the queue, returns reference to write-end of the -- queue and IO action of the actor. Because newActor only returns -- ActorQ, caller of newActor can only send messages to -- created actor. Caller cannot receive message from the queue. -- -- Inbox, or read-end of the queue, is passed to user supplied -- message handler so the handler can receive message to the actor. If -- the handler need to send a message to itself, wrap the message queue -- by ActorQ constructor then use send over created -- ActorQ. Here is an example. -- --
-- send (ActorQ yourInbox) message --newActor :: ActorHandler message result -> IO (Actor message result) -- | Create a new actor with bounded inbox queue. newBoundedActor :: InboxLength -> ActorHandler message result -> IO (Actor message result) -- | MonitoredAction is type synonym of function with callback on -- termination installed. Its type signature fits to argument for -- forkIOWithUnmask. type MonitoredAction = (IO () -> IO ()) -> IO () -- | ExitReason indicates reason of thread termination. data ExitReason -- | Thread was normally finished. Normal :: ExitReason -- | A synchronous exception was thrown and it was not caught. This -- indicates some unhandled error happened inside of the thread handler. UncaughtException :: SomeException -> ExitReason -- | An asynchronous exception was thrown. This also happen when the thread -- was killed by supervisor. Killed :: ExitReason -- | Monitor is user supplied callback function which is called when -- monitored thread is terminated. type Monitor = ExitReason " Reason of thread termination." -> ThreadId " ID of terminated thread." -> IO () -- | Install Monitor callback function to simple IO action. watch :: Monitor -> IO () -> MonitoredAction -- | Install another Monitor callback function to -- MonitoredAction. nestWatch :: Monitor -> MonitoredAction -> MonitoredAction -- | Convert simple IO action to MonitoredAction without installing -- Monitor. noWatch :: IO () -> MonitoredAction -- | Restart defines when terminated child thread triggers restart -- operation by its supervisor. Restart only defines when it -- triggers restart operation. It does not directly means if the thread -- will be or will not be restarted. It is determined by restart strategy -- of supervisor. For example, a static Temporary child never -- triggers restart on its termination but static Temporary child -- will be restarted if another Permanent or Transient -- thread with common supervisor triggered restart operation and the -- supervisor has OneForAll strategy. data Restart -- | Permanent thread always triggers restart. Permanent :: Restart -- | Transient thread triggers restart only if it was terminated by -- exception. Transient :: Restart -- | Temporary thread never triggers restart. Temporary :: Restart -- | ChildSpec is representation of IO action which can be -- supervised by supervisor. Supervisor can run the IO action with -- separate thread, watch its termination and restart it based on restart -- type. data ChildSpec -- | Create a ChildSpec from plain IO action. newChildSpec :: Restart -> IO () -> ChildSpec -- | Create a ChildSpec from MonitoredAction. newMonitoredChildSpec :: Restart -> MonitoredAction -> ChildSpec -- | Add a Monitor function to existing ChildSpec. addMonitor :: Monitor -> ChildSpec -> ChildSpec -- | RestartSensitivity defines condition how supervisor determines -- intensive restart is happening. If more than -- restartSensitivityIntensity time of restart is triggered within -- restartSensitivityPeriod, supervisor decides intensive restart -- is happening and it terminates itself. Default intensity (maximum -- number of acceptable restart) is 1. Default period is 5 seconds. data RestartSensitivity RestartSensitivity :: Int -> TimeSpec -> RestartSensitivity -- | Maximum number of restart accepted within the period below. [restartSensitivityIntensity] :: RestartSensitivity -> Int -- | Length of time window in TimeSpec where the number of restarts -- is counted. [restartSensitivityPeriod] :: RestartSensitivity -> TimeSpec -- | IntenseRestartDetector keeps data used for detecting intense -- restart. It keeps maxR (maximum restart intensity), maxT (period of -- majoring restart intensity) and history of restart with system -- timestamp in Monotonic form. data IntenseRestartDetector -- | Create new IntenseRestartDetector with given RestartSensitivity -- parameters. newIntenseRestartDetector :: RestartSensitivity -> IntenseRestartDetector -- | Determine if the last restart results intensive restart. It pushes the -- last restart timestamp to the DelayedQueue of restart history -- held inside of the IntenseRestartDetector then check if the oldest -- restart record is pushed out from the queue. If no record was pushed -- out, there are less number of restarts than limit, so it is not -- intensive. If a record was pushed out, it means we had one more -- restarts than allowed. If the oldest restart and newest restart -- happened within allowed time interval, it is intensive. -- -- This function implements pure part of detectIntenseRestartNow. detectIntenseRestart :: IntenseRestartDetector -> TimeSpec -> (Bool, IntenseRestartDetector) -- | Determine if intensive restart is happening now. It is called when -- restart is triggered by some thread termination. detectIntenseRestartNow :: IntenseRestartDetector -> IO (Bool, IntenseRestartDetector) -- | Restart strategy of supervisor data Strategy -- | Restart only exited thread. OneForOne :: Strategy -- | Restart all threads supervised by the same supervisor of exited -- thread. OneForAll :: Strategy -- | Type synonym for write-end of supervisor's message queue. type SupervisorQueue = ActorQ SupervisorMessage -- | Create a supervisor. -- -- When created supervisor IO action started, it automatically creates -- child threads based on given ChildSpec list and supervise them. -- After it created such static children, it listens given -- SupervisorQueue. User can let the supervisor creates dynamic -- child thread by calling newChild. Dynamic child threads created -- by newChild are also supervised. -- -- When the supervisor thread is killed or terminated in some reason, all -- children including static children and dynamic children are all -- killed. -- -- With OneForOne restart strategy, when a child thread -- terminated, it is restarted based on its restart type given in -- ChildSpec. If the terminated thread has Permanent -- restart type, supervisor restarts it regardless its exit reason. If -- the terminated thread has Transient restart type, and -- termination reason is other than Normal (meaning -- UncaughtException or Killed), it is restarted. If the -- terminated thread has Temporary restart type, supervisor does -- not restart it regardless its exit reason. -- -- Created IO action is designed to run in separate thread from main -- thread. If you try to run the IO action at main thread without having -- producer of the supervisor queue you gave, the supervisor will dead -- lock. newSupervisor :: Strategy -> RestartSensitivity -> [ChildSpec] -> ActorHandler SupervisorMessage () -- | Create a supervisor with OneForOne restart strategy and has no -- static ChildSpec. When it started, it has no child threads. -- Only newChild can add new thread supervised by the supervisor. -- Thus the simple one-for-one supervisor only manages dynamic and -- Temporary children. newSimpleOneForOneSupervisor :: ActorHandler SupervisorMessage () -- | Ask the supervisor to spawn new temporary child thread. Returns -- ThreadId of the new child. newChild :: CallTimeout -> SupervisorQueue -> ChildSpec -> IO (Maybe ThreadId) -- | Create a new finite state machine. -- -- The state machine waits for new message at Inbox then callback -- user supplied message handler. The message handler must return -- Right with new state or Left with final result. When -- Right is returned, the state machine waits for next message. -- When Left is returned, the state machine terminates and returns -- the result. -- -- newStateMachine returns an IO action wrapping the state machine -- described above. The returned IO action can be executed within an -- Async or bare thread. -- -- Created IO action is designed to run in separate thread from main -- thread. If you try to run the IO action at main thread without having -- producer of the message queue you gave, the state machine will dead -- lock. newStateMachine :: state -> (state -> message -> IO (Either result state)) -> ActorHandler message result -- | create an unbound actor of newStateMachine. Short-cut of following. -- --
-- newActor $ newStateMachine initialState messageHandler --newStateMachineActor :: state -> (state -> message -> IO (Either result state)) -> IO (Actor message result) -- | Timeout of call method for server behavior in microseconds. Default is -- 5 second. newtype CallTimeout CallTimeout :: Int -> CallTimeout -- | Type synonym of callback function to obtain return value. type ServerCallback a = (a -> IO ()) -- | Send an asynchronous request to a server. cast :: ActorQ cmd -> cmd -> IO () -- | Send an synchronous request to a server and waits for a return value -- until timeout. call :: CallTimeout -> ActorQ cmd -> (ServerCallback a -> cmd) -> IO (Maybe a) -- | Make an asynchronous call to a server and give result in CPS style. -- The return value is delivered to given callback function. It also can -- fail by timeout. Calling thread can wait for a return value -- from the callback. -- -- Use this function with care because there is no guaranteed -- cancellation of background worker thread other than timeout. Giving -- infinite timeout (zero) to the CallTimeout argument may cause -- the background thread left to run, possibly indefinitely. callAsync :: CallTimeout -> ActorQ cmd -> (ServerCallback a -> cmd) -> (Maybe a -> IO b) -> IO (Async b) -- | Send an request to a server but ignore return value. callIgnore :: ActorQ cmd -> (ServerCallback a -> cmd) -> IO ()