-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | The Cloud Haskell Application Platform
--
-- Modelled after Erlang OTP's gen_server, this framework provides
-- similar facilities for Cloud Haskell, grouping essential practices for
-- client/server development into a set of modules and standards designed
-- to help you build concurrent, distributed applications with relative
-- ease.
@package distributed-process-client-server
@version 0.1.1
-- | Unsafe variant of the Managed Process Client API. This module
-- implements the client portion of a Managed Process using the unsafe
-- variants of cloud haskell's messaging primitives. It relies on the
-- -extras implementation of UnsafePrimitives, which forces
-- evaluation for types that provide an NFData instance. Direct
-- use of the underlying unsafe primitives (from the distributed-process
-- library) without NFData instances is unsupported.
--
-- IMPORTANT NOTE: As per the platform documentation, it is not possible
-- to guarantee that an NFData instance will force
-- evaluation in the same way that a Binary instance would (when
-- encoding to a byte string). Please read the unsafe primitives
-- documentation carefully and make sure you know what you're doing. You
-- have been warned.
--
-- See Control.Distributed.Process.Extras. See
-- Control.Distributed.Process.Extras.UnsafePrimitives. See
-- Control.Distributed.Process.UnsafePrimitives.
module Control.Distributed.Process.ManagedProcess.UnsafeClient
-- | Send a control message over a ControlPort. This version of
-- shutdown uses unsafe primitives.
sendControlMessage :: Serializable m => ControlPort m -> m -> Process ()
-- | Send a signal instructing the process to terminate. This version of
-- shutdown uses unsafe primitives.
shutdown :: ProcessId -> Process ()
-- | Make a synchronous call - uses unsafe primitives.
call :: (Addressable s, NFSerializable a, NFSerializable b) => s -> a -> Process b
-- | Safe version of call that returns information about the error
-- if the operation fails - uses unsafe primitives.
safeCall :: (Addressable s, NFSerializable a, NFSerializable b) => s -> a -> Process (Either ExitReason b)
-- | Version of safeCall that returns Nothing if the
-- operation fails. Uses unsafe primitives.
tryCall :: (Addressable s, NFSerializable a, NFSerializable b) => s -> a -> Process (Maybe b)
-- | Make a synchronous call, but timeout and return Nothing if a
-- reply is not received within the specified time interval - uses
-- unsafe primitives.
callTimeout :: (Addressable s, NFSerializable a, NFSerializable b) => s -> a -> TimeInterval -> Process (Maybe b)
flushPendingCalls :: NFSerializable b => TimeInterval -> (b -> Process b) -> Process (Maybe b)
-- | Invokes call out of band, and returns an "async handle."
-- Uses unsafe primitives.
callAsync :: (Addressable s, NFSerializable a, NFSerializable b) => s -> a -> Process (Async b)
-- | Sends a cast message to the server identified by
-- server - uses unsafe primitives.
cast :: (Addressable a, NFSerializable m) => a -> m -> Process ()
-- | Sends a channel message to the server and returns a
-- ReceivePort - uses unsafe primitives.
callChan :: (Addressable s, NFSerializable a, NFSerializable b) => s -> a -> Process (ReceivePort b)
syncCallChan :: (Addressable s, NFSerializable a, NFSerializable b) => s -> a -> Process b
syncSafeCallChan :: (Addressable s, NFSerializable a, NFSerializable b) => s -> a -> Process (Either ExitReason b)
module Control.Distributed.Process.ManagedProcess.Server.Priority
prioritiseCall :: (Serializable a, Serializable b) => (s -> a -> Priority b) -> DispatchPriority s
prioritiseCall_ :: (Serializable a, Serializable b) => (a -> Priority b) -> DispatchPriority s
prioritiseCast :: Serializable a => (s -> a -> Priority ()) -> DispatchPriority s
prioritiseCast_ :: Serializable a => (a -> Priority ()) -> DispatchPriority s
prioritiseInfo :: Serializable a => (s -> a -> Priority ()) -> DispatchPriority s
prioritiseInfo_ :: Serializable a => (a -> Priority ()) -> DispatchPriority s
setPriority :: Int -> Priority m
-- | The Server Portion of the Managed Process API.
module Control.Distributed.Process.ManagedProcess.Server
-- | Creates a Condition from a function that takes a process state
-- a and an input message b and returns a Bool
-- indicating whether the associated handler should run.
condition :: (Serializable a, Serializable b) => (a -> b -> Bool) -> Condition a b
-- | Create a Condition from a function that takes a process state
-- a and returns a Bool indicating whether the associated
-- handler should run.
state :: Serializable m => (s -> Bool) -> Condition s m
-- | Creates a Condition from a function that takes an input message
-- m and returns a Bool indicating whether the associated
-- handler should run.
input :: Serializable m => (m -> Bool) -> Condition s m
-- | Instructs the process to send a reply and continue running.
reply :: Serializable r => r -> s -> Process (ProcessReply r s)
-- | Instructs the process to send a reply and evaluate the
-- ProcessAction.
replyWith :: Serializable r => r -> ProcessAction s -> Process (ProcessReply r s)
-- | Instructs the process to skip sending a reply and evaluate a
-- ProcessAction
noReply :: Serializable r => ProcessAction s -> Process (ProcessReply r s)
-- | Instructs the process to continue running and receiving messages.
continue :: s -> Process (ProcessAction s)
-- | Instructs the process loop to wait for incoming messages until
-- Delay is exceeded. If no messages are handled during this
-- period, the timeout handler will be called. Note that this
-- alters the process timeout permanently such that the given
-- Delay will remain in use until changed.
timeoutAfter :: Delay -> s -> Process (ProcessAction s)
-- | Instructs the process to hibernate for the given
-- TimeInterval. Note that no messages will be removed from the
-- mailbox until after hibernation has ceased. This is equivalent to
-- calling threadDelay.
hibernate :: TimeInterval -> s -> Process (ProcessAction s)
-- | Instructs the process to terminate, giving the supplied reason. If a
-- valid shutdownHandler is installed, it will be called with the
-- ExitReason returned from this call, along with the process
-- state.
stop :: ExitReason -> Process (ProcessAction s)
-- | As stop, but provides an updated state for the shutdown
-- handler.
stopWith :: s -> ExitReason -> Process (ProcessAction s)
-- | Sends a reply explicitly to a caller.
--
--
-- replyTo = sendTo
--
replyTo :: Serializable m => CallRef m -> m -> Process ()
-- | Sends a reply to a SendPort (for use in handleRpcChan et
-- al).
--
--
-- replyChan = sendChan
--
replyChan :: Serializable m => SendPort m -> m -> Process ()
-- | Continue without giving a reply to the caller - equivalent to
-- continue, but usable in a callback passed to the
-- handleCall family of functions.
noReply_ :: Serializable r => s -> Process (ProcessReply r s)
-- | Halt process execution during a call handler, without paying any
-- attention to the expected return type.
haltNoReply_ :: Serializable r => ExitReason -> Process (ProcessReply r s)
-- | Version of continue that can be used in handlers that ignore
-- process state.
continue_ :: s -> Process (ProcessAction s)
-- | Version of timeoutAfter that can be used in handlers that
-- ignore process state.
--
--
-- action (\(TimeoutPlease duration) -> timeoutAfter_ duration)
--
timeoutAfter_ :: Delay -> (s -> Process (ProcessAction s))
-- | Version of hibernate that can be used in handlers that ignore
-- process state.
--
--
-- action (\(HibernatePlease delay) -> hibernate_ delay)
--
hibernate_ :: TimeInterval -> (s -> Process (ProcessAction s))
-- | Version of stop that can be used in handlers that ignore
-- process state.
--
--
-- action (\ClientError -> stop_ ExitNormal)
--
stop_ :: ExitReason -> (s -> Process (ProcessAction s))
-- | Constructs a call handler from a function in the
-- Process monad. > handleCall = handleCallIf (const True)
handleCall :: (Serializable a, Serializable b) => (s -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | Constructs a call handler from an ordinary function in the
-- Process monad. Given a function f :: (s -> a ->
-- Process (ProcessReply b s)), the expression handleCall f
-- will yield a Dispatcher for inclusion in a Behaviour
-- specification for the GenProcess. Messages are only dispatched
-- to the handler if the supplied condition evaluates to True.
handleCallIf :: (Serializable a, Serializable b) => Condition s a -> (s -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | As handleCall but passes the CallRef to the handler
-- function. This can be useful if you wish to reply later to the
-- caller by, e.g., spawning a process to do some work and have it
-- replyTo caller response out of band. In this case the
-- callback can pass the CallRef to the worker (or stash it away
-- itself) and return noReply.
handleCallFrom :: (Serializable a, Serializable b) => (s -> CallRef b -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | As handleCallFrom but only runs the handler if the supplied
-- Condition evaluates to True.
handleCallFromIf :: (Serializable a, Serializable b) => Condition s a -> (s -> CallRef b -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | Creates a handler for a typed channel RPC style interaction.
-- The handler takes a SendPort b to reply to, the initial input
-- and evaluates to a ProcessAction. It is the handler code's
-- responsibility to send the reply to the SendPort.
handleRpcChan :: (Serializable a, Serializable b) => (s -> SendPort b -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | As handleRpcChan, but only evaluates the handler if the
-- supplied condition is met.
handleRpcChanIf :: (Serializable a, Serializable b) => Condition s a -> (s -> SendPort b -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Constructs a cast handler from an ordinary function in the
-- Process monad. > handleCast = handleCastIf (const True)
handleCast :: Serializable a => (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Constructs a cast handler from an ordinary function in the
-- Process monad. Given a function f :: (s -> a ->
-- Process (ProcessAction s)), the expression handleCall f
-- will yield a Dispatcher for inclusion in a Behaviour
-- specification for the GenProcess.
handleCastIf :: Serializable a => Condition s a -> (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Creates a generic input handler (i.e., for received messages that are
-- not sent using the cast or call APIs) from an
-- ordinary function in the Process monad.
handleInfo :: Serializable a => (s -> a -> Process (ProcessAction s)) -> DeferredDispatcher s
-- | Handle completely raw input messages.
handleRaw :: (s -> Message -> Process (ProcessAction s)) -> DeferredDispatcher s
-- | Constructs a handler for both call and cast messages.
-- handleDispatch = handleDispatchIf (const True)
handleDispatch :: Serializable a => (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Constructs a handler for both call and cast messages.
-- Messages are only dispatched to the handler if the supplied condition
-- evaluates to True. Handlers defined in this way have no
-- access to the call context (if one exists) and cannot therefore reply
-- to calls.
handleDispatchIf :: Serializable a => Condition s a -> (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Creates an exit handler scoped to the execution of any and all
-- the registered call, cast and info handlers for the process.
handleExit :: Serializable a => (s -> ProcessId -> a -> Process (ProcessAction s)) -> ExitSignalDispatcher s
handleExitIf :: Serializable a => (s -> a -> Bool) -> (s -> ProcessId -> a -> Process (ProcessAction s)) -> ExitSignalDispatcher s
-- | Constructs an action handler. Like handleDispatch this
-- can handle both cast and call messages, but you
-- won't know which you're dealing with. This can be useful where certain
-- inputs require a definite action, such as stopping the server, without
-- concern for the state (e.g., when stopping we need only decide to
-- stop, as the terminate handler can deal with state cleanup etc). For
-- example:
--
--
-- action (MyCriticalSignal -> stop_ ExitNormal)
--
action :: Serializable a => (a -> (s -> Process (ProcessAction s))) -> Dispatcher s
-- | Constructs a call handler from a function in the
-- Process monad. The handler expression returns the reply, and
-- the action will be set to continue.
--
--
-- handleCall_ = handleCallIf_ $ input (const True)
--
handleCall_ :: (Serializable a, Serializable b) => (a -> Process b) -> Dispatcher s
-- | Constructs a call handler from an ordinary function in the
-- Process monad. This variant ignores the state argument present
-- in handleCall and handleCallIf and is therefore useful
-- in a stateless server. Messges are only dispatched to the handler if
-- the supplied condition evaluates to True
--
-- See handleCall
handleCallIf_ :: (Serializable a, Serializable b) => Condition s a -> (a -> Process b) -> Dispatcher s
-- | A variant of handleCallFrom_ that ignores the state argument.
handleCallFrom_ :: (Serializable a, Serializable b) => (CallRef b -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | A variant of handleCallFromIf that ignores the state argument.
handleCallFromIf_ :: (Serializable a, Serializable b) => (Condition s a) -> (CallRef b -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | A variant of handleRpcChan that ignores the state argument.
handleRpcChan_ :: (Serializable a, Serializable b) => (SendPort b -> a -> Process (ProcessAction ())) -> Dispatcher ()
-- | A variant of handleRpcChanIf that ignores the state argument.
handleRpcChanIf_ :: (Serializable a, Serializable b) => Condition () a -> (SendPort b -> a -> Process (ProcessAction ())) -> Dispatcher ()
-- | Version of handleCast that ignores the server state.
handleCast_ :: Serializable a => (a -> (s -> Process (ProcessAction s))) -> Dispatcher s
-- | Version of handleCastIf that ignores the server state.
handleCastIf_ :: Serializable a => Condition s a -> (a -> (s -> Process (ProcessAction s))) -> Dispatcher s
-- | Constructs a control channel handler from a function in the
-- Process monad. The handler expression returns no reply, and the
-- control message is treated in the same fashion as a
-- cast.
--
--
-- handleControlChan = handleControlChanIf $ input (const True)
--
handleControlChan :: Serializable a => ControlChannel a -> (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Version of handleControlChan that ignores the server state.
handleControlChan_ :: Serializable a => ControlChannel a -> (a -> (s -> Process (ProcessAction s))) -> Dispatcher s
-- | A safe variant of the Server Portion of the Managed
-- Process API. Most of these operations have the same names as
-- similar operations in the impure Server module (re-exported
-- by the primary API in ManagedProcess). To remove the
-- ambiguity, some combination of either qualification and/or the
-- hiding clause will be required.
--
--
-- - Restricted Server Callbacks
--
--
-- The idea behind this module is to provide safe callbacks, i.e.,
-- server code that is free from side effects. This safety is enforced by
-- the type system via the RestrictedProcess monad. A StateT
-- interface is provided for code running in the
-- RestrictedProcess monad, so that server side state can be
-- managed safely without resorting to IO (or code running in the
-- Process monad).
module Control.Distributed.Process.ManagedProcess.Server.Restricted
-- | Restricted (i.e., pure, free from side effects) execution environment
-- for callcastinfo handlers to execute in.
data RestrictedProcess s a
-- | The result of a call handler's execution.
data Result a
-- | reply with the given term
Reply :: a -> Result a
-- | reply with the given term and enter timeout
Timeout :: Delay -> a -> Result a
-- | reply with the given term and hibernate
Hibernate :: TimeInterval -> a -> Result a
-- | stop the process with the given reason
Stop :: ExitReason -> Result a
-- | The result of a safe cast handler's execution.
data RestrictedAction
-- | continue executing
RestrictedContinue :: RestrictedAction
-- | timeout if no messages are received
RestrictedTimeout :: Delay -> RestrictedAction
-- | hibernate (i.e., sleep)
RestrictedHibernate :: TimeInterval -> RestrictedAction
-- | stop/terminate the server process
RestrictedStop :: ExitReason -> RestrictedAction
-- | A version of
-- "Control.Distributed.Process.ManagedProcess.Server.handleCall" that
-- takes a handler which executes in RestrictedProcess.
handleCall :: (Serializable a, Serializable b) => (a -> RestrictedProcess s (Result b)) -> Dispatcher s
-- | A version of
-- "Control.Distributed.Process.ManagedProcess.Server.handleCallIf" that
-- takes a handler which executes in RestrictedProcess.
handleCallIf :: (Serializable a, Serializable b) => (Condition s a) -> (a -> RestrictedProcess s (Result b)) -> Dispatcher s
-- | A version of
-- "Control.Distributed.Process.ManagedProcess.Server.handleCast" that
-- takes a handler which executes in RestrictedProcess.
handleCast :: Serializable a => (a -> RestrictedProcess s RestrictedAction) -> Dispatcher s
-- | A version of
-- "Control.Distributed.Process.ManagedProcess.Server.handleCastIf" that
-- takes a handler which executes in RestrictedProcess.
handleCastIf :: Serializable a => Condition s a -> (a -> RestrictedProcess s RestrictedAction) -> Dispatcher s
-- | A version of
-- "Control.Distributed.Process.ManagedProcess.Server.handleInfo" that
-- takes a handler which executes in RestrictedProcess.
handleInfo :: Serializable a => (a -> RestrictedProcess s RestrictedAction) -> DeferredDispatcher s
handleExit :: Serializable a => (a -> RestrictedProcess s RestrictedAction) -> ExitSignalDispatcher s
handleTimeout :: (Delay -> RestrictedProcess s RestrictedAction) -> TimeoutHandler s
-- | Put a new process state state
putState :: s -> RestrictedProcess s ()
-- | Get the current process state
getState :: RestrictedProcess s s
-- | Apply the given expression to the current process state
modifyState :: (s -> s) -> RestrictedProcess s ()
-- | Instructs the process to send a reply and continue running.
reply :: Serializable r => r -> RestrictedProcess s (Result r)
-- | Continue without giving a reply to the caller - equivalent to
-- continue, but usable in a callback passed to the
-- handleCall family of functions.
noReply :: Serializable r => Result r -> RestrictedProcess s (Result r)
-- | Halt process execution during a call handler, without paying any
-- attention to the expected return type.
haltNoReply :: Serializable r => ExitReason -> RestrictedProcess s (Result r)
-- | Instructs the process to continue running and receiving messages.
continue :: RestrictedProcess s RestrictedAction
-- | Instructs the process loop to wait for incoming messages until
-- Delay is exceeded. If no messages are handled during this
-- period, the timeout handler will be called. Note that this
-- alters the process timeout permanently such that the given
-- Delay will remain in use until changed.
timeoutAfter :: Delay -> RestrictedProcess s RestrictedAction
-- | Instructs the process to hibernate for the given
-- TimeInterval. Note that no messages will be removed from the
-- mailbox until after hibernation has ceased. This is equivalent to
-- evaluating liftIO . threadDelay.
hibernate :: TimeInterval -> RestrictedProcess s RestrictedAction
-- | Instructs the process to terminate, giving the supplied reason. If a
-- valid shutdownHandler is installed, it will be called with the
-- ExitReason returned from this call, along with the process
-- state.
stop :: ExitReason -> RestrictedProcess s RestrictedAction
-- | Log a trace message using the underlying Process's say
say :: String -> RestrictedProcess s ()
instance Typeable RestrictedProcess
instance Typeable Result
instance Functor (RestrictedProcess s)
instance Monad (RestrictedProcess s)
instance MonadState s (RestrictedProcess s)
instance MonadIO (RestrictedProcess s)
instance Applicative (RestrictedProcess s)
-- | The Client Portion of the Managed Process API.
module Control.Distributed.Process.ManagedProcess.Client
-- | Send a control message over a ControlPort.
sendControlMessage :: Serializable m => ControlPort m -> m -> Process ()
-- | Send a signal instructing the process to terminate. The receive
-- loop which manages the process mailbox will prioritise
-- Shutdown signals higher than any other incoming messages, but
-- the server might be busy (i.e., still in the process of excuting a
-- handler) at the time of sending however, so the caller should not make
-- any assumptions about the timeliness with which the shutdown signal
-- will be handled. If responsiveness is important, a better approach
-- might be to send an exit signal with Shutdown as the
-- reason. An exit signal will interrupt any operation currently underway
-- and force the running process to clean up and terminate.
shutdown :: ProcessId -> Process ()
-- | Make a synchronous call - will block until a reply is received. The
-- calling process will exit with ExitReason if the calls fails.
call :: (Addressable s, Serializable a, Serializable b) => s -> a -> Process b
-- | Safe version of call that returns information about the error
-- if the operation fails. If an error occurs then the explanation will
-- be will be stashed away as (ExitOther String).
safeCall :: (Addressable s, Serializable a, Serializable b) => s -> a -> Process (Either ExitReason b)
-- | Version of safeCall that returns Nothing if the
-- operation fails. If you need information about *why* a call has failed
-- then you should use safeCall or combine catchExit and
-- call instead.
tryCall :: (Addressable s, Serializable a, Serializable b) => s -> a -> Process (Maybe b)
-- | Make a synchronous call, but timeout and return Nothing if a
-- reply is not received within the specified time interval.
--
-- If the result of the call is a failure (or the call was cancelled)
-- then the calling process will exit, with the ExitReason given
-- as the reason. If the call times out however, the semantics on the
-- server side are undefined, i.e., the server may or may not
-- successfully process the request and may (or may not) send a response
-- at a later time. From the callers perspective, this is somewhat
-- troublesome, since the call result cannot be decoded directly. In this
-- case, the flushPendingCalls API may be used to attempt
-- to receive the message later on, however this makes no attempt
-- whatsoever to guarantee which call response will in fact be
-- returned to the caller. In those semantics are unsuited to your
-- application, you might choose to exit or die in case
-- of a timeout, or alternatively, use the callAsync API and
-- associated waitTimeout function (in the Async API),
-- which takes a re-usable handle on which to wait (with timeouts)
-- multiple times.
callTimeout :: (Addressable s, Serializable a, Serializable b) => s -> a -> TimeInterval -> Process (Maybe b)
flushPendingCalls :: Serializable b => TimeInterval -> (b -> Process b) -> Process (Maybe b)
-- | Invokes call out of band, and returns an async
-- handle.
callAsync :: (Addressable s, Serializable a, Serializable b) => s -> a -> Process (Async b)
-- | Sends a cast message to the server identified by
-- server. The server will not send a response. Like Cloud
-- Haskell's send primitive, cast is fully asynchronous and
-- never fails - therefore casting to a non-existent (e.g.,
-- dead) server process will not generate an error.
cast :: (Addressable a, Serializable m) => a -> m -> Process ()
-- | Sends a channel message to the server and returns a
-- ReceivePort on which the reponse can be delivered, if the
-- server so chooses (i.e., the might ignore the request or crash).
callChan :: (Addressable s, Serializable a, Serializable b) => s -> a -> Process (ReceivePort b)
-- | A synchronous version of callChan.
syncCallChan :: (Addressable s, Serializable a, Serializable b) => s -> a -> Process b
-- | A safe version of syncCallChan, which returns Left
-- ExitReason if the call fails.
syncSafeCallChan :: (Addressable s, Serializable a, Serializable b) => s -> a -> Process (Either ExitReason b)
-- | This module provides a high(er) level API for building complex
-- Process implementations by abstracting out the management of
-- the process' mailbox, reply/response handling, timeouts, process
-- hiberation, error handling and shutdown/stop procedures. It is
-- modelled along similar lines to OTP's gen_server API -
-- http://www.erlang.org/doc/man/gen_server.html.
--
-- In particular, a managed process will interoperate cleanly with
-- the supervisor API in distributed-process-supervision.
--
--
--
-- Once started, a managed process will consume messages from its
-- mailbox and pass them on to user defined handlers based on the
-- types received (mapped to those accepted by the handlers) and
-- optionally by also evaluating user supplied predicates to determine
-- which handler(s) should run. Each handler returns a
-- ProcessAction which specifies how we should proceed. If none of
-- the handlers is able to process a message (because their types are
-- incompatible), then the unhandledMessagePolicy will be applied.
--
-- The ProcessAction type defines the ways in which our process
-- can respond to its inputs, whether by continuing to read incoming
-- messages, setting an optional timeout, sleeping for a while or
-- stopping. The optional timeout behaves a little differently to the
-- other process actions. If no messages are received within the
-- specified time span, a user defined timeoutHandler will be
-- called in order to determine the next action.
--
-- The ProcessDefinition type also defines a
-- shutdownHandler, which is called whenever the process exits,
-- whether because a callback has returned stop as the next
-- action, or as the result of unhandled exit signal or similar
-- asynchronous exceptions thrown in (or to) the process itself.
--
-- The other handlers are split into two groups: apiHandlers and
-- infoHandlers. The former contains handlers for the cast
-- and call protocols, whilst the latter contains handlers that
-- deal with input messages which are not sent via these API calls (i.e.,
-- messages sent using bare send or signals put into the process
-- mailbox by the node controller, such as
-- ProcessMonitorNotification and the like).
--
--
-- - The Cast/Call Protocol
--
--
-- Deliberate interactions with a managed process usually fall
-- into one of two categories. A cast interaction involves a
-- client sending a message asynchronously and the server handling this
-- input. No reply is sent to the client. On the other hand, a
-- call is a remote procedure call, where the client sends
-- a message and waits for a reply from the server.
--
-- All expressions given to apiHandlers have to conform to the
-- cast|call protocol. The protocol (messaging) implementation is
-- hidden from the user; API functions for creating user defined
-- apiHandlers are given instead, which take expressions (i.e.,
-- a function or lambda expression) and create the appropriate
-- Dispatcher for handling the cast (or call).
--
-- These castcall protocols are for dealing with expected/ inputs.
-- They will usually form the explicit public API for the process, and be
-- exposed by providing module level functions that defer to the
-- cast/call API, giving the author an opportunity to enforce the correct
-- types. For example:
--
--
-- {- Ask the server to add two numbers -}
-- add :: ProcessId -> Double -> Double -> Double
-- add pid x y = call pid (Add x y)
--
--
-- Note here that the return type from the call is inferred and
-- will not be enforced by the type system. If the server sent a
-- different type back in the reply, then the caller might be blocked
-- indefinitely! In fact, the result of mis-matching the expected return
-- type (in the client facing API) with the actual type returned by the
-- server is more severe in practise. The underlying types that implement
-- the call protocol carry information about the expected return
-- type. If there is a mismatch between the input and output types that
-- the client API uses and those which the server declares it can handle,
-- then the message will be considered unroutable - no handler will be
-- executed against it and the unhandled message policy will be applied.
-- You should, therefore, take great care to align these types since the
-- default unhandled message policy is to terminate the server! That
-- might seem pretty extreme, but you can alter the unhandled message
-- policy and/or use the various overloaded versions of the call API in
-- order to detect errors on the server such as this.
--
-- The cost of potential type mismatches between the client and server is
-- the main disadvantage of this looser coupling between them. This
-- mechanism does however, allow servers to handle a variety of messages
-- without specifying the entire protocol to be supported in excruciating
-- detail.
--
--
-- - Handling Unexpected/Info Messages
--
--
-- An explicit protocol for communicating with the process can be
-- configured using cast and call, but it is not possible
-- to prevent other kinds of messages from being sent to the process
-- mailbox. When any message arrives for which there are no handlers able
-- to process its content, the UnhandledMessagePolicy will be
-- applied. Sometimes it is desireable to process incoming messages which
-- aren't part of the protocol, rather than let the policy deal with
-- them. This is particularly true when incoming messages are important
-- to the process, but their point of origin is outside the author's
-- control. Handling signals such as
-- ProcessMonitorNotification is a typical example of this:
--
--
-- handleInfo_ (\(ProcessMonitorNotification _ _ r) -> say $ show r >> continue_)
--
--
--
-- - Handling Process State
--
--
-- The ProcessDefinition is parameterised by the type of state it
-- maintains. A process that has no state will have the type
-- ProcessDefinition () and can be bootstrapped by evaluating
-- statelessProcess.
--
-- All call/cast handlers come in two flavours, those which take the
-- process state as an input and those which do not. Handlers that ignore
-- the process state have to return a function that takes the state and
-- returns the required action. Versions of the various action generating
-- functions ending in an underscore are provided to simplify this:
--
--
-- statelessProcess {
-- apiHandlers = [
-- handleCall_ (\(n :: Int) -> return (n * 2))
-- , handleCastIf_ (\(c :: String, _ :: Delay) -> c == "timeout")
-- (\("timeout", (d :: Delay)) -> timeoutAfter_ d)
-- ]
-- , timeoutHandler = \_ _ -> stop $ ExitOther "timeout"
-- }
--
--
--
-- - Avoiding Side Effects
--
--
-- If you wish to only write side-effect free code in your server
-- definition, then there is an explicit API for doing so. Instead of
-- using the handlers definition functions in this module, import the
-- pure server module instead, which provides a StateT based monad
-- for building referentially transparent callbacks.
--
-- See
-- Control.Distributed.Process.ManagedProcess.Server.Restricted
-- for details and API documentation.
--
--
--
-- Error handling appears in several contexts and process definitions can
-- hook into these with relative ease. Only process failures as a result
-- of asynchronous exceptions are supported by the API, which provides
-- several scopes for error handling.
--
-- Catching exceptions inside handler functions is no different to
-- ordinary exception handling in monadic code.
--
--
-- handleCall (\x y ->
-- catch (hereBeDragons x y)
-- (\(e :: SmaugTheTerribleException) ->
-- return (Left (show e))))
--
--
-- The caveats mentioned in Control.Distributed.Process.Extras
-- about exit signal handling obviously apply here as well.
--
--
-- - Structured Exit Handling
--
--
-- Because Control.Distributed.Process.ProcessExitException is a
-- ubiquitous signalling mechanism in Cloud Haskell, it is treated unlike
-- other asynchronous exceptions. The ProcessDefinition
-- exitHandlers field accepts a list of handlers that, for a
-- specific exit reason, can decide how the process should respond. If
-- none of these handlers matches the type of reason then the
-- process will exit with DiedException why. In addition, a
-- private exit handler is installed for exit signals where
-- reason :: ExitReason, which is a form of exit signal
-- used explicitly by the supervision APIs. This behaviour, which cannot
-- be overriden, is to gracefully shut down the process, calling the
-- shutdownHandler as usual, before stopping with
-- reason given as the final outcome.
--
-- Example: handling custom data is ProcessExitException
--
--
-- handleExit (\state from (sigExit :: SomeExitData) -> continue s)
--
--
-- Under some circumstances, handling exit signals is perfectly
-- legitimate. Handling of other forms of asynchronous exception
-- (e.g., exceptions not generated by an exit signal) is not
-- supported by this API. Cloud Haskell's primitives for exception
-- handling will work normally in managed process callbacks
-- however.
--
-- If any asynchronous exception goes unhandled, the process will
-- immediately exit without running the shutdownHandler. It is
-- very important to note that in Cloud Haskell, link failures generate
-- asynchronous exceptions in the target and these will NOT be caught by
-- the API and will therefore cause the process to exit without
-- running the termination handler callback. If your termination
-- handler is set up to do important work (such as resource cleanup) then
-- you should avoid linking you process and use monitors instead.
--
--
-- - Prioritised Mailboxes
--
--
-- Many processes need to prioritise certain classes of message over
-- others, so two subsets of the API are given to supporting those cases.
--
-- A PrioritisedProcessDefintion combines the usual
-- ProcessDefintion - containing the cast/call API, error,
-- termination and info handlers - with a list of Priority
-- entries, which are used at runtime to prioritise the server's inputs.
-- Note that it is only messages which are prioritised; The server's
-- various handlers are still evaluated in insertion order.
--
-- Prioritisation does not guarantee that a prioritised message/type will
-- be processed before other traffic - indeed doing so in a
-- multi-threaded runtime would be very hard - but in the absence of
-- races between multiple processes, if two messages are both present in
-- the process' own mailbox, they will be applied to the
-- ProcessDefinition's handler's in priority order. This is achieved by
-- draining the real mailbox into a priority queue and processing each
-- message in turn.
--
-- A prioritised process must be configured with a Priority list
-- to be of any use. Creating a prioritised process without any
-- priorities would be a big waste of computational resources, and it is
-- worth thinking carefully about whether or not prioritisation is truly
-- necessary in your design before choosing to use it.
--
-- Using a prioritised process is as simple as calling pserve
-- instead of serve, and passing an initialised
-- PrioritisedProcessDefinition.
--
--
--
-- For advanced users and those requiring very low latency, a prioritised
-- process definition might not be suitable, since it performs
-- considerable work behind the scenes. There are also designs
-- that need to segregate a process' control plane from other
-- kinds of traffic it is expected to receive. For such use cases, a
-- control channel may prove a better choice, since typed channels
-- are already prioritised during the mailbox scans that the base
-- receiveWait and receiveTimeout primitives from
-- distribute-process provides.
--
-- In order to utilise a control channel in a server, it must be
-- passed to the corresponding handleControlChan function (or its
-- stateless variant). The control channel is created by evaluating
-- newControlChan, in the same way that we create regular typed
-- channels.
--
-- In order for clients to communicate with a server via its control
-- channel however, they must pass a handle to a ControlPort,
-- which can be obtained by evaluating channelControlPort on the
-- ControlChannel. A ControlPort is Serializable,
-- so they can alternatively be sent to other processes.
--
-- Control channel traffic will only be prioritised over other
-- traffic if the handlers using it are present before others (e.g.,
-- handleInfo, handleCast, etc) in the process definition. It is
-- not possible to combine prioritised processes with control
-- channels. Attempting to do so will satisfy the compiler, but crash
-- with a runtime error once you attempt to evaluate the prioritised
-- server loop (i.e., pserve).
--
-- Since the primary purpose of control channels is to simplify and
-- optimise client-server communication over a single channel, this
-- module provides an alternate server loop in the form of
-- chanServe. Instead of passing an initialised
-- ProcessDefinition, this API takes an expression from a
-- ControlChannel to ProcessDefinition, operating in the
-- Process monad. Providing the opaque reference in this fashion
-- is useful, since the type of messages the control channel carries will
-- not correlate directly to the inter-process traffic we use internally.
--
-- Although control channels are intended for use as a single control
-- plane (via chanServe), it is possible to use them as a
-- more strictly typed communications backbone, since they do enforce
-- absolute type safety in client code, being bound to a particular type
-- on creation. For rpc (i.e., call) interaction however, it is
-- not possible to have the server reply to a control channel, since
-- they're a one way pipe. It is possible to alleviate this
-- situation by passing a request type than contains a typed channel
-- bound to the expected reply type, enabling client and server to match
-- on both the input and output types as specifically as possible. Note
-- that this still does not guarantee an agreement on types between all
-- parties at runtime however.
--
-- An example of how to do this follows:
--
--
-- data Request = Request String (SendPort String)
-- deriving (Typeable, Generic)
-- instance Binary Request where
--
-- -- note that our initial caller needs an mvar to obtain the control port...
-- echoServer :: MVar (ControlPort Request) -> Process ()
-- echoServer mv = do
-- cc <- newControlChan :: Process (ControlChannel Request)
-- liftIO $ putMVar mv $ channelControlPort cc
-- let s = statelessProcess {
-- apiHandlers = [
-- handleControlChan_ cc (\(Request m sp) -> sendChan sp m >> continue_)
-- ]
-- }
-- serve () (statelessInit Infinity) s
--
-- echoClient :: String -> ControlPort Request -> Process String
-- echoClient str cp = do
-- (sp, rp) <- newChan
-- sendControlMessage cp $ Request str sp
-- receiveChan rp
--
--
--
-- - Performance Considerations
--
--
-- The various server loops are fairly optimised, but there is a
-- definite cost associated with scanning the mailbox to match on
-- protocol messages, plus additional costs in space and time due to
-- mapping over all available info handlers for non-protocol
-- (i.e., neither call nor cast) messages. These are
-- exacerbated significantly when using prioritisation, whilst using a
-- single control channel is very fast and carries little overhead.
--
-- From the client perspective, it's important to remember that the
-- call protocol will wait for a reply in most cases, triggering a
-- full O(n) scan of the caller's mailbox. If the mailbox is extremely
-- full and calls are regularly made, this may have a significant impact
-- on the caller. The callChan family of client API functions
-- can alleviate this, by using (and matching on) a private typed channel
-- instead, but the server must be written to accomodate this. Similar
-- gains can be had using a control channel and providing a typed
-- reply channel in the request data, however the call mechanism
-- does not support this notion, so not only are we unable to use the
-- various reply functions, client code should also consider
-- monitoring the server's pid and handling server failures whilst
-- waiting on
module Control.Distributed.Process.ManagedProcess
-- | Return type for and InitHandler expression.
data InitResult s
InitOk :: s -> Delay -> InitResult s
InitStop :: String -> InitResult s
InitIgnore :: InitResult s
-- | An expression used to initialise a process with its state.
type InitHandler a s = a -> Process (InitResult s)
-- | Starts the message handling loop for a managed process
-- configured with the supplied process definition, after calling the
-- init handler with its initial arguments. Note that this function does
-- not return until the server exits.
serve :: a -> InitHandler a s -> ProcessDefinition s -> Process ()
-- | Starts the message handling loop for a prioritised managed
-- process, configured with the supplied process definition, after
-- calling the init handler with its initial arguments. Note that this
-- function does not return until the server exits.
pserve :: a -> InitHandler a s -> PrioritisedProcessDefinition s -> Process ()
-- | Starts the message handling loop for a managed process,
-- configured with a typed control channel. The caller supplied
-- expression is evaluated with an opaque reference to the channel, which
-- must be passed when calling handleControlChan. The meaning
-- and behaviour of the init handler and initial arguments are the same
-- as those given to serve. Note that this function does not
-- return until the server exits.
chanServe :: Serializable b => a -> InitHandler a s -> (ControlChannel b -> Process (ProcessDefinition s)) -> Process ()
-- | Wraps any process loop and ensures that it adheres to the
-- managed process start/stop semantics, i.e., evaluating the
-- InitHandler with an initial state and delay will either
-- die due to InitStop, exit silently (due to
-- InitIgnore) or evaluate the process' loop. The
-- supplied loop must evaluate to ExitNormal, otherwise
-- the calling processing will die with whatever
-- ExitReason is given.
runProcess :: (s -> Delay -> Process ExitReason) -> a -> InitHandler a s -> Process ()
-- | Turns a standard ProcessDefinition into a
-- PrioritisedProcessDefinition, by virtue of the supplied list of
-- DispatchPriority expressions.
prioritised :: ProcessDefinition s -> [DispatchPriority s] -> PrioritisedProcessDefinition s
-- | Stores the functions that determine runtime behaviour in response to
-- incoming messages and a policy for responding to unhandled messages.
data ProcessDefinition s
ProcessDefinition :: [Dispatcher s] -> [DeferredDispatcher s] -> [ExitSignalDispatcher s] -> TimeoutHandler s -> ShutdownHandler s -> UnhandledMessagePolicy -> ProcessDefinition s
-- | functions that handle call/cast messages
apiHandlers :: ProcessDefinition s -> [Dispatcher s]
-- | functions that handle non call/cast messages
infoHandlers :: ProcessDefinition s -> [DeferredDispatcher s]
-- | functions that handle exit signals
exitHandlers :: ProcessDefinition s -> [ExitSignalDispatcher s]
-- | a function that handles timeouts
timeoutHandler :: ProcessDefinition s -> TimeoutHandler s
-- | a function that is run just before the process exits
shutdownHandler :: ProcessDefinition s -> ShutdownHandler s
-- | how to deal with unhandled messages
unhandledMessagePolicy :: ProcessDefinition s -> UnhandledMessagePolicy
-- | A ProcessDefinition decorated with DispatchPriority
-- for certain input domains.
data PrioritisedProcessDefinition s
PrioritisedProcessDefinition :: ProcessDefinition s -> [DispatchPriority s] -> RecvTimeoutPolicy -> PrioritisedProcessDefinition s
processDef :: PrioritisedProcessDefinition s -> ProcessDefinition s
priorities :: PrioritisedProcessDefinition s -> [DispatchPriority s]
recvTimeout :: PrioritisedProcessDefinition s -> RecvTimeoutPolicy
-- | For a PrioritisedProcessDefinition, this policy determines for
-- how long the receive loop should continue draining the process'
-- mailbox before processing its received mail (in priority order).
--
-- If a prioritised managed process is receiving a lot of messages
-- (into its real mailbox), the server might never get around to
-- actually processing its inputs. This (mandatory) policy provides a
-- guarantee that eventually (i.e., after a specified number of received
-- messages or time interval), the server will stop removing messages
-- from its mailbox and process those it has already received.
data RecvTimeoutPolicy
RecvCounter :: Int -> RecvTimeoutPolicy
RecvTimer :: TimeInterval -> RecvTimeoutPolicy
newtype Priority a
Priority :: Int -> Priority a
getPrio :: Priority a -> Int
data DispatchPriority s
-- | Provides dispatch from cast and call messages to a typed handler.
data Dispatcher s
-- | Provides dispatch for any input, returns Nothing for unhandled
-- messages.
data DeferredDispatcher s
-- | An expression used to handle process termination.
type ShutdownHandler s = s -> ExitReason -> Process ()
-- | An expression used to handle process timeouts.
type TimeoutHandler s = s -> Delay -> Process (ProcessAction s)
-- | The action taken by a process after a handler has run and its updated
-- state. See continue timeoutAfter hibernate
-- stop stopWith
data ProcessAction s
-- | continue with (possibly new) state
ProcessContinue :: s -> ProcessAction s
-- | timeout if no messages are received
ProcessTimeout :: Delay -> s -> ProcessAction s
-- | hibernate for delay
ProcessHibernate :: TimeInterval -> s -> ProcessAction s
-- | stop the process, giving ExitReason
ProcessStop :: ExitReason -> ProcessAction s
-- | stop the process with ExitReason, with updated state
ProcessStopping :: s -> ExitReason -> ProcessAction s
-- | Returned from handlers for the synchronous call protocol,
-- encapsulates the reply data and the action to take after
-- sending the reply. A handler can return NoReply if they wish
-- to ignore the call.
data ProcessReply r s
-- | Wraps a predicate that is used to determine whether or not a handler
-- is valid based on some combination of the current process state, the
-- type and/or value of the input message or both.
data Condition s m
-- | An expression used to handle a call message.
type CallHandler s a b = s -> a -> Process (ProcessReply b s)
-- | An expression used to handle a cast message.
type CastHandler s a = s -> a -> Process (ProcessAction s)
-- | Policy for handling unexpected messages, i.e., messages which are not
-- sent using the call or cast APIs, and which are not
-- handled by any of the handleInfo handlers.
data UnhandledMessagePolicy
-- | stop immediately, giving ExitOther UnhandledInput as
-- the reason
Terminate :: UnhandledMessagePolicy
-- | forward the message to the given recipient
DeadLetter :: ProcessId -> UnhandledMessagePolicy
-- | log messages, then behave identically to Drop
Log :: UnhandledMessagePolicy
-- | dequeue and then drop/ignore the message
Drop :: UnhandledMessagePolicy
data CallRef a
-- | Provides a means for servers to listen on a separate, typed
-- control channel, thereby segregating the channel from their
-- regular (and potentially busy) mailbox.
data ControlChannel m
-- | The writable end of a ControlChannel.
data ControlPort m
-- | A default ProcessDefinition, with no api, info or exit handler.
-- The default timeoutHandler simply continues, the
-- shutdownHandler is a no-op and the
-- unhandledMessagePolicy is Terminate.
defaultProcess :: ProcessDefinition s
-- | Creates a default PrioritisedProcessDefinition from a list of
-- DispatchPriority. See defaultProcess for the underlying
-- definition.
defaultProcessWithPriorities :: [DispatchPriority s] -> PrioritisedProcessDefinition s
-- | A basic, stateless ProcessDefinition. See defaultProcess
-- for the default field values.
statelessProcess :: ProcessDefinition ()
-- | A default, state unaware InitHandler that can be used
-- with statelessProcess. This simply returns InitOk with
-- the empty state (i.e., unit) and the given Delay.
statelessInit :: Delay -> InitHandler () ()
-- | Constructs a call handler from a function in the
-- Process monad. > handleCall = handleCallIf (const True)
handleCall :: (Serializable a, Serializable b) => (s -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | Constructs a call handler from an ordinary function in the
-- Process monad. Given a function f :: (s -> a ->
-- Process (ProcessReply b s)), the expression handleCall f
-- will yield a Dispatcher for inclusion in a Behaviour
-- specification for the GenProcess. Messages are only dispatched
-- to the handler if the supplied condition evaluates to True.
handleCallIf :: (Serializable a, Serializable b) => Condition s a -> (s -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | As handleCall but passes the CallRef to the handler
-- function. This can be useful if you wish to reply later to the
-- caller by, e.g., spawning a process to do some work and have it
-- replyTo caller response out of band. In this case the
-- callback can pass the CallRef to the worker (or stash it away
-- itself) and return noReply.
handleCallFrom :: (Serializable a, Serializable b) => (s -> CallRef b -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | As handleCallFrom but only runs the handler if the supplied
-- Condition evaluates to True.
handleCallFromIf :: (Serializable a, Serializable b) => Condition s a -> (s -> CallRef b -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | Constructs a cast handler from an ordinary function in the
-- Process monad. > handleCast = handleCastIf (const True)
handleCast :: Serializable a => (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Constructs a cast handler from an ordinary function in the
-- Process monad. Given a function f :: (s -> a ->
-- Process (ProcessAction s)), the expression handleCall f
-- will yield a Dispatcher for inclusion in a Behaviour
-- specification for the GenProcess.
handleCastIf :: Serializable a => Condition s a -> (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Creates a generic input handler (i.e., for received messages that are
-- not sent using the cast or call APIs) from an
-- ordinary function in the Process monad.
handleInfo :: Serializable a => (s -> a -> Process (ProcessAction s)) -> DeferredDispatcher s
-- | Handle completely raw input messages.
handleRaw :: (s -> Message -> Process (ProcessAction s)) -> DeferredDispatcher s
-- | Creates a handler for a typed channel RPC style interaction.
-- The handler takes a SendPort b to reply to, the initial input
-- and evaluates to a ProcessAction. It is the handler code's
-- responsibility to send the reply to the SendPort.
handleRpcChan :: (Serializable a, Serializable b) => (s -> SendPort b -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | As handleRpcChan, but only evaluates the handler if the
-- supplied condition is met.
handleRpcChanIf :: (Serializable a, Serializable b) => Condition s a -> (s -> SendPort b -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Constructs an action handler. Like handleDispatch this
-- can handle both cast and call messages, but you
-- won't know which you're dealing with. This can be useful where certain
-- inputs require a definite action, such as stopping the server, without
-- concern for the state (e.g., when stopping we need only decide to
-- stop, as the terminate handler can deal with state cleanup etc). For
-- example:
--
--
-- action (MyCriticalSignal -> stop_ ExitNormal)
--
action :: Serializable a => (a -> (s -> Process (ProcessAction s))) -> Dispatcher s
-- | Constructs a handler for both call and cast messages.
-- handleDispatch = handleDispatchIf (const True)
handleDispatch :: Serializable a => (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Creates an exit handler scoped to the execution of any and all
-- the registered call, cast and info handlers for the process.
handleExit :: Serializable a => (s -> ProcessId -> a -> Process (ProcessAction s)) -> ExitSignalDispatcher s
-- | Constructs a call handler from a function in the
-- Process monad. The handler expression returns the reply, and
-- the action will be set to continue.
--
--
-- handleCall_ = handleCallIf_ $ input (const True)
--
handleCall_ :: (Serializable a, Serializable b) => (a -> Process b) -> Dispatcher s
-- | A variant of handleCallFrom_ that ignores the state argument.
handleCallFrom_ :: (Serializable a, Serializable b) => (CallRef b -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | Constructs a call handler from an ordinary function in the
-- Process monad. This variant ignores the state argument present
-- in handleCall and handleCallIf and is therefore useful
-- in a stateless server. Messges are only dispatched to the handler if
-- the supplied condition evaluates to True
--
-- See handleCall
handleCallIf_ :: (Serializable a, Serializable b) => Condition s a -> (a -> Process b) -> Dispatcher s
-- | A variant of handleCallFromIf that ignores the state argument.
handleCallFromIf_ :: (Serializable a, Serializable b) => (Condition s a) -> (CallRef b -> a -> Process (ProcessReply b s)) -> Dispatcher s
-- | Version of handleCast that ignores the server state.
handleCast_ :: Serializable a => (a -> (s -> Process (ProcessAction s))) -> Dispatcher s
-- | Version of handleCastIf that ignores the server state.
handleCastIf_ :: Serializable a => Condition s a -> (a -> (s -> Process (ProcessAction s))) -> Dispatcher s
-- | A variant of handleRpcChan that ignores the state argument.
handleRpcChan_ :: (Serializable a, Serializable b) => (SendPort b -> a -> Process (ProcessAction ())) -> Dispatcher ()
-- | A variant of handleRpcChanIf that ignores the state argument.
handleRpcChanIf_ :: (Serializable a, Serializable b) => Condition () a -> (SendPort b -> a -> Process (ProcessAction ())) -> Dispatcher ()
-- | Creates a new ControlChannel.
newControlChan :: Serializable m => Process (ControlChannel m)
-- | Obtain an opaque expression for communicating with a
-- ControlChannel.
channelControlPort :: Serializable m => ControlChannel m -> ControlPort m
-- | Constructs a control channel handler from a function in the
-- Process monad. The handler expression returns no reply, and the
-- control message is treated in the same fashion as a
-- cast.
--
--
-- handleControlChan = handleControlChanIf $ input (const True)
--
handleControlChan :: Serializable a => ControlChannel a -> (s -> a -> Process (ProcessAction s)) -> Dispatcher s
-- | Version of handleControlChan that ignores the server state.
handleControlChan_ :: Serializable a => ControlChannel a -> (a -> (s -> Process (ProcessAction s))) -> Dispatcher s
-- | Creates a Condition from a function that takes a process state
-- a and an input message b and returns a Bool
-- indicating whether the associated handler should run.
condition :: (Serializable a, Serializable b) => (a -> b -> Bool) -> Condition a b
-- | Create a Condition from a function that takes a process state
-- a and returns a Bool indicating whether the associated
-- handler should run.
state :: Serializable m => (s -> Bool) -> Condition s m
-- | Creates a Condition from a function that takes an input message
-- m and returns a Bool indicating whether the associated
-- handler should run.
input :: Serializable m => (m -> Bool) -> Condition s m
-- | Instructs the process to send a reply and continue running.
reply :: Serializable r => r -> s -> Process (ProcessReply r s)
-- | Instructs the process to send a reply and evaluate the
-- ProcessAction.
replyWith :: Serializable r => r -> ProcessAction s -> Process (ProcessReply r s)
-- | Instructs the process to skip sending a reply and evaluate a
-- ProcessAction
noReply :: Serializable r => ProcessAction s -> Process (ProcessReply r s)
-- | Continue without giving a reply to the caller - equivalent to
-- continue, but usable in a callback passed to the
-- handleCall family of functions.
noReply_ :: Serializable r => s -> Process (ProcessReply r s)
-- | Halt process execution during a call handler, without paying any
-- attention to the expected return type.
haltNoReply_ :: Serializable r => ExitReason -> Process (ProcessReply r s)
-- | Instructs the process to continue running and receiving messages.
continue :: s -> Process (ProcessAction s)
-- | Version of continue that can be used in handlers that ignore
-- process state.
continue_ :: s -> Process (ProcessAction s)
-- | Instructs the process loop to wait for incoming messages until
-- Delay is exceeded. If no messages are handled during this
-- period, the timeout handler will be called. Note that this
-- alters the process timeout permanently such that the given
-- Delay will remain in use until changed.
timeoutAfter :: Delay -> s -> Process (ProcessAction s)
-- | Version of timeoutAfter that can be used in handlers that
-- ignore process state.
--
--
-- action (\(TimeoutPlease duration) -> timeoutAfter_ duration)
--
timeoutAfter_ :: Delay -> (s -> Process (ProcessAction s))
-- | Instructs the process to hibernate for the given
-- TimeInterval. Note that no messages will be removed from the
-- mailbox until after hibernation has ceased. This is equivalent to
-- calling threadDelay.
hibernate :: TimeInterval -> s -> Process (ProcessAction s)
-- | Version of hibernate that can be used in handlers that ignore
-- process state.
--
--
-- action (\(HibernatePlease delay) -> hibernate_ delay)
--
hibernate_ :: TimeInterval -> (s -> Process (ProcessAction s))
-- | Instructs the process to terminate, giving the supplied reason. If a
-- valid shutdownHandler is installed, it will be called with the
-- ExitReason returned from this call, along with the process
-- state.
stop :: ExitReason -> Process (ProcessAction s)
-- | As stop, but provides an updated state for the shutdown
-- handler.
stopWith :: s -> ExitReason -> Process (ProcessAction s)
-- | Version of stop that can be used in handlers that ignore
-- process state.
--
--
-- action (\ClientError -> stop_ ExitNormal)
--
stop_ :: ExitReason -> (s -> Process (ProcessAction s))
-- | Sends a reply explicitly to a caller.
--
--
-- replyTo = sendTo
--
replyTo :: Serializable m => CallRef m -> m -> Process ()
-- | Sends a reply to a SendPort (for use in handleRpcChan et
-- al).
--
--
-- replyChan = sendChan
--
replyChan :: Serializable m => SendPort m -> m -> Process ()