distributed-process-extras- Cloud Haskell Extras

Safe HaskellNone




Cloud Haskell Extras
Evaluation Strategies and Support for NFData

When sending messages to a local process (i.e., intra-node), the default approach is to encode (i.e., serialise) the message anyway, just to ensure that no unevaluated thunks are passed to the receiver. In distributed-process, you must explicitly choose to use unsafe primitives that do nothing to ensure evaluation, since this might cause an error in the receiver which would be difficult to debug. Using NFData, it is possible to force evaluation, but there is no way to ensure that both the NFData and Binary instances do so in the same way (i.e., to the same depth, etc) therefore automatic use of NFData is not possible in distributed-process.

By contrast, distributed-process-platform makes extensive use of NFData to force evaluation (and avoid serialisation overheads during intra-node communication), via the NFSerializable type class. This does nothing to fix the potential disparity between NFData and Binary instances, so you should verify that your data is being handled as expected (e.g., by sticking to strict fields, or some such) and bear in mind that things could go wrong.

The UnsafePrimitives module in this library will force evaluation before calling the UnsafePrimitives in distributed-process, which - if you've vetted everything correctly - should provide a bit more safety, whilst still keeping performance at an acceptable level.

Users of the various service and utility models (such as ManagedProcess and the Service and Task APIs) should consult the sub-system specific documentation for instructions on how to utilise these features.

IMPORTANT NOTICE: Despite the apparent safety of forcing evaluation before sending, we still cannot make any actual guarantees about the evaluation semantics of these operations, and therefore the unsafe moniker will remain in place, in one form or another, for all functions and modules that use them.

Error/Exception Handling

It is important not to be too general when catching exceptions in cloud haskell application, because asynchonous exceptions provide cloud haskell with its process termination mechanism. Two exception types in particular, signal the instigator's intention to stop a process immediately, which are raised (i.e., thrown) in response to the kill and exit primitives provided by the base distributed-process package.

You should generally try to keep exception handling code to the lowest (i.e., most specific) scope possible. If you wish to trap exit signals, use the various flavours of catchExit primitive from distributed-process.


Exported Types

class (Resolvable a, Routable a) => Addressable a Source


class Resolvable a where Source

Class of things that can be resolved to a ProcessId.


resolve :: a -> Process (Maybe ProcessId) Source

Resolve the reference to a process id, or Nothing if resolution fails

class Routable a where Source

Provides a unified API for addressing processes.

Minimal complete definition

sendTo, unsafeSendTo


sendTo :: Serializable m => a -> m -> Process () Source

Send a message to the target asynchronously

unsafeSendTo :: NFSerializable m => a -> m -> Process () Source

Send some NFData message to the target asynchronously, forcing evaluation (i.e., deepseq) beforehand.

unresolvableMessage :: a -> String Source

Unresolvable Addressable Message

class Linkable a where Source

Class of things to which a Process can link itself.


linkTo :: a -> Process () Source

Create a link with the supplied object.

class Killable a where Source

Class of things that can be killed (or instructed to exit).


killProc :: a -> String -> Process () Source

exitProc :: Serializable m => a -> m -> Process () Source

class (NFData a, Serializable a) => NFSerializable a Source

Introduces a class that brings NFData into scope along with Serializable, such that we can force evaluation. Intended for use with the UnsafePrimitives module (which wraps Control.Distributed.Process.UnsafePrimitives), and guarantees evaluatedness in terms of NFData. Please note that we cannot guarantee that an NFData instance will behave the same way as a Binary one with regards evaluation, so it is still possible to introduce unexpected behaviour by using unsafe primitives in this way.


data Shutdown Source

A ubiquitous shutdown signal that can be used to maintain a consistent shutdown/stop protocol for any process that wishes to handle it.



data ExitReason Source

Provides a reason for process termination.



indicates normal exit


normal response to a Shutdown

ExitOther !String

abnormal (error) shutdown

type Channel a = (SendPort a, ReceivePort a) Source

Simple representation of a channel.

type Tag = Int Source

Tags provide uniqueness for messages, so that they can be matched with their response.

type TagPool = MVar Tag Source

Generates unique Tag for messages and response pairs. Each process that depends, directly or indirectly, on the call mechanisms in Control.Distributed.Process.Global.Call should have at most one TagPool on which to draw unique message tags.

Primitives overriding those in distributed-process

monitor :: Resolvable a => a -> Process (Maybe MonitorRef) Source

Monitor any Resolvable object.

Utilities and Extended Primitives

spawnSignalled :: Process a -> (a -> Process ()) -> Process ProcessId Source

Spawn a new (local) process. This variant takes an initialisation action and a secondary expression from the result of the initialisation to Process (). The spawn operation synchronises on the completion of the before action, such that the calling process is guaranteed to only see the newly spawned ProcessId once the initialisation has successfully completed.

spawnLinkLocal :: Process () -> Process ProcessId Source

Node local version of spawnLink. Note that this is just the sequential composition of spawn and link. (The Unified semantics that underlies Cloud Haskell does not even support a synchronous link operation)

spawnMonitorLocal :: Process () -> Process (ProcessId, MonitorRef) Source

Like spawnLinkLocal, but monitors the spawned process.

linkOnFailure :: ProcessId -> Process () Source

CH's link primitive, unlike Erlang's, will trigger when the target process dies for any reason. This function has semantics like Erlang's: it will trigger ProcessLinkException only when the target dies abnormally.

times :: Int -> Process () -> Process () Source

Apply the supplied expression n times

matchCond :: Serializable a => (a -> Maybe (Process b)) -> Match b Source

An alternative to matchIf that allows both predicate and action to be expressed in one parameter.

deliver :: (Addressable a, Serializable m) => m -> a -> Process () Source

awaitResponse :: Addressable a => a -> [Match (Either ExitReason b)] -> Process (Either ExitReason b) Source

Safe (i.e., monitored) waiting on an expected response/message.

Call/Tagging support

newTagPool :: Process TagPool Source

Create a new per-process source of unique message identifiers.

getTag :: TagPool -> Process Tag Source

Extract a new identifier from a TagPool.

Registration and Process Lookup

whereisOrStart :: String -> Process () -> Process ProcessId Source

Returns the pid of the process that has been registered under the given name. This refers to a local, per-node registration, not global registration. If that name is unregistered, a process is started. This is a handy way to start per-node named servers.

whereisOrStartRemote :: NodeId -> String -> Closure (Process ()) -> Process (Maybe ProcessId) Source

A remote equivalent of whereisOrStart. It deals with the node registry on the given node, and the process, if it needs to be started, will run on that node. If the node is inaccessible, Nothing will be returned.