@@ -274,23 +274,39 @@ executeTask :: forall s a . (Addressable s, Serializable a)
274
274
executeTask sid t = call sid t
275
275
{% endhighlight %}
276
276
277
- Although ` call ` is a synchronous protocol, communication with the
278
- * server process* is out of band, both from the client and the server's
279
- point of view. The server implementation chooses whether to reply to a
280
- call request immediately, or defer its reply until a later stage (and
281
- thus go back to receiving other messages in the meanwhile).
282
-
283
- In terms of code, that's all there is to it for our client! Note that
284
- the type signature we expose to our consumers is specific, and that
285
- we do not expose them to either arbitrary messages arriving in their
286
- mailbox or to exceptions being thrown in their thread. Instead we
287
- return an ` Either ` . One very important thing about this approach is
288
- that if the server replies with some other type (i.e., a type other
289
- than ` Either String a ` ) then our client will be blocked indefinitely!
290
-
291
- There are several varieties of the ` call ` API that deal with error
292
- handling in different ways. Consult the haddocks for more info about
293
- these.
277
+ Remember that in Cloud Haskell, the only way to communicate with a process
278
+ (apart from introducing scoped concurrency primitives like ` MVar ` or using
279
+ stm) is via its mailbox and typed channels. Also, all communication with
280
+ the process is asynchronous from the sender's perspective and synchronous
281
+ from the receiver's. Although ` call ` is a synchronous (RPC-like) protocol,
282
+ communication with the * server process* has to take place out of band.
283
+
284
+ The server implementation chooses to reply to each request and when handling
285
+ a ` call ` , can defer its reply until a later stage, thus going back to
286
+ receiving and processing other messages in the meantime. As far as the client
287
+ is concerned, it is simply waiting for a reply. Note that the ` call ` primitive
288
+ is implemented so that messages from other processes cannot interleave with
289
+ the server's response. This is very important, since another message of type
290
+ ` Either String a ` could theoretically arrive in our mailbox from somewhere
291
+ else whilst we're receiving, therefore ` call ` transparently tags the call
292
+ message and awaits a specific reply from the server (containing the same
293
+ tag). These tags are guaranteed to be unique across multiple nodes, since
294
+ they're based on a ` MonitorRef ` , which holds a ` Identifier ProcessId ` and
295
+ a node local monitor ref counter. All monitor creation is coordinated by
296
+ the caller's node controller (guaranteeing the uniqueness of the ref
297
+ counter for the lifetime of the node) and the references are not easily
298
+ forged (i.e., sent by mistake - this is not a security feature of any sort)
299
+ since the type is opaque.
300
+
301
+ In terms of code for the client then, that's all there is to it!
302
+ Note that the type signature we expose to our consumers is specific, and that
303
+ we do not expose them to either arbitrary messages arriving in their mailbox
304
+ or to exceptions being thrown in their thread. Instead we return an ` Either ` .
305
+ One very important thing about this approach is that if the server replies
306
+ with some other type (i.e., a type other than ` Either String a ` ) then our
307
+ client will be blocked indefinitely! We could alleviate this by using a
308
+ typed channel as we saw previously with our math server, but there's little
309
+ point since we're in total charge of both client and server.
294
310
295
311
### Implementing the server
296
312
0 commit comments