=head1 Message Passing for the Non-Blocked Mind

=head1 Introduction and Terminology

This is a tutorial about how to get the swing of the new L<AnyEvent::MP>
module, which allows programs to transparently pass messages within the
process and to other processes on the same or a different host.

What kind of messages? Basically a message here means a list of Perl
strings, numbers, hashes and arrays, anything that can be expressed as a
L<JSON> text (as JSON is used by default in the protocol). Here are two
examples:

    write_log => 1251555874, "action was successful.\n"
    123, ["a", "b", "c"], { foo => "bar" }

When using L<AnyEvent::MP> it is customary to use a descriptive string as
first element of a message, that indictes the type of the message. This
element is called a I<tag> in L<AnyEvent::MP>, as some API functions
(C<rcv>) support matching it directly.

Supposedly you want to send a ping message with your current time to
somewhere, this is how such a message might look like (in Perl syntax):

   ping => 1251381636

Now that we know what a message is, to which entities are those
messages being I<passed>? They are I<passed> to I<ports>. A I<port> is
a destination for messages but also a context to execute code: when
a runtime error occurs while executing code belonging to a port, the
exception will be raised on the port and can even travel to interested
parties on other nodes, which makes supervision of distributed processes
easy.

How do these ports relate to things you know? Each I<port> belongs
to a I<node>, and a I<node> is just the UNIX process that runs your
L<AnyEvent::MP> application.

Each I<node> is distinguished from other I<nodes> running on the same or
another host in a network by its I<node ID>. A I<node ID> is simply a
unique string chosen manually or assigned by L<AnyEvent::MP> in some way
(UNIX nodename, random string...).

Here is a diagram about how I<nodes>, I<ports> and UNIX processes relate
to each other. The setup consists of two nodes (more are of course
possible): Node C<A> (in UNIX process 7066) with the ports C<ABC> and
C<DEF>. And the node C<B> (in UNIX process 8321) with the ports C<FOO> and
C<BAR>.


  |- PID: 7066 -|                  |- PID: 8321 -|
  |             |                  |             |
  | Node ID: A  |                  | Node ID: B  |
  |             |                  |             |
  |   Port ABC =|= <----\ /-----> =|= Port FOO   |
  |             |        X         |             |
  |   Port DEF =|= <----/ \-----> =|= Port BAR   |
  |             |                  |             |
  |-------------|                  |-------------|

The strings for the I<port IDs> here are just for illustrative
purposes: Even though I<ports> in L<AnyEvent::MP> are also identified by
strings, they can't be choosen manually and are assigned by the system
dynamically. These I<port IDs> are unique within a network and can also be
used to identify senders or as message tags for instance.

The next sections will explain the API of L<AnyEvent::MP> by going through
a few simple examples. Later some more complex idioms are introduced,
which are hopefully useful to solve some real world problems.

=head1 Passing Your First Message

As a start lets have a look at the messaging API. The following example
is just a demo to show the basic elements of message passing with
L<AnyEvent::MP>.

The example should print: C<Ending with: 123>, in a rather complicated
way, by passing some message to a port.

   use AnyEvent;
   use AnyEvent::MP;

   my $end_cv = AnyEvent->condvar;

   my $port = port;

   rcv $port, test => sub {
      my ($data) = @_;
      $end_cv->send ($data);
   };

   snd $port, test => 123;

   print "Ending with: " . $end_cv->recv . "\n";

It already uses most of the essential functions inside
L<AnyEvent::MP>: First there is the C<port> function which will create a
I<port> and will return it's I<port ID>, a simple string.

This I<port ID> can be used to send messages to the port and install
handlers to receive messages on the port. Since it is a simple string
it can be safely passed to other I<nodes> in the network when you want
to refer to that specific port (usually used for RPC, where you need
to tell the other end which I<port> to send the reply to - messages in
L<AnyEvent::MP> have a destination, but no source).

The next function is C<rcv>:

   rcv $port, test => sub { ... };

It installs a receiver callback on the I<port> that specified as the first
argument (it only works for "local" ports, i.e. ports created on the same
node). The next argument, in this example C<test>, specifies a I<tag> to
match. This means that whenever a message with the first element being
the string C<test> is received, the callback is called with the remaining
parts of that message.

Messages can be sent with the C<snd> function, which is used like this in
the example above:

   snd $port, test => 123;

This will send the message C<'test', 123> to the I<port> with the I<port
ID> stored in C<$port>. Since in this case the receiver has a I<tag> match
on C<test> it will call the callback with the first argument being the
number C<123>.

The callback is a typicall AnyEvent idiom: the callback just passes
that number on to the I<condition variable> C<$end_cv> which will then
pass the value to the print. Condition variables are out of the scope
of this tutorial and not often used with ports, so please consult the
L<AnyEvent::Intro> about them.

Passing messages inside just one process is boring. Before we can move on
and do interprocess message passing we first have to make sure some things
have been set up correctly for our nodes to talk to each other.

=head1 System Requirements and System Setup

Before we can start with real IPC we have to make sure some things work on
your system.

First we have to setup a I<shared secret>: for two L<AnyEvent::MP>
I<nodes> to be able to communicate with each other over the network it is
necessary to setup the same I<shared secret> for both of them, so they can
prove their trustworthyness to each other.

The easiest way is to set this up is to use the F<aemp> utility:

   aemp gensecret

This creates a F<$HOME/.perl-anyevent-mp> config file and generates a
random shared secret. You can copy this file to any other system and
then communicate over the network (via TCP) with it. You can also select
your own shared secret (F<aemp setsecret>) and for increased security
requirements you can even create (or configure) a TLS certificate (F<aemp
gencert>), causing connections to not just be securely authenticated, but
also to be encrypted and protected against tinkering.

Connections will only be successfully established when the I<nodes>
that want to connect to each other have the same I<shared secret> (or
successfully verify the TLS certificate of the other side, in which case
no shared secret is required).

B<If something does not work as expected, and for example tcpdump shows
that the connections are closed almost immediately, you should make sure
that F<~/.perl-anyevent-mp> is the same on all hosts/user accounts that
you try to connect with each other!>

Thats is all for now, you will find some more advanced fiddling with the
C<aemp> utility later.


=head1 Passing Messages Between Processes

=head2 The Receiver

Lets split the previous example up into two programs: one that contains
the sender and one for the receiver. First the receiver application, in
full:

   use AnyEvent;
   use AnyEvent::MP;
   use AnyEvent::MP::Global;

   initialise_node "eg_simple_receiver";

   my $port = port;

   AnyEvent::MP::Global::register $port, "eg_receivers";

   rcv $port, test => sub {
      my ($data, $reply_port) = @_;

      print "Received data: " . $data . "\n";
   };

   AnyEvent->condvar->recv;

=head3 AnyEvent::MP::Global

Now, that wasn't too bad, was it? Ok, let's step through the new functions
and modules that have been used.

For starters, there is now an additional module being
used: L<AnyEvent::MP::Global>. This module provides us with a I<global
registry>, which lets us register ports in groups that are visible on all
I<nodes> in a network.

What is this useful for? Well, the I<port IDs> are random-looking strings,
assigned by L<AnyEvent::MP>. We cannot know those I<port IDs> in advance,
so we don't know which I<port ID> to send messages to, especially when the
message is to be passed between different I<nodes> (or UNIX processes). To
find the right I<port> of another I<node> in the network we will need
to communicate this somehow to the sender. And exactly that is what
L<AnyEvent::MP::Global> provides.

Especially in larger, more anonymous networks this is handy: imagine you
have a few database backends, a few web frontends and some processing
distributed over a number of hosts: all of these would simply register
themselves in the appropriate group, and your web frontends can start to
find some database backend.

=head3 C<initialise_node> And The Network

Now, let's have a look at the new function, C<initialise_node>:

   initialise_node "eg_simple_receiver";

Before we are able to send messages to other nodes we have to initialise
ourself to become a "distributed node". Initialising a node means naming
the node, optionally binding some TCP listeners so that other nodes can
contact it and connecting to a predefined set of seed addresses so the
node can discover the existing network - and the existing network can
discover the node!

The first argument, the string C<"eg_simple_receiver">, is the so-called
I<profile> to use: A profile holds some information about the application
that is going to be a node in an L<AnyEvent::MP> network. Customarily you
don't specify a profile name at all: in this case, AnyEvent::MP will use
the POSIX nodename.

The profile allows you to set the I<node ID> that your application will
use (the node ID defaults to the profile name if not specified). You can
also set I<binds> in the profile, meaning that you can define TCP ports
that the application will listen on for incoming connections from other
nodes of the network.

You should also configure I<seeds> in the profile: A I<seed> is just a
TCP address of some other node in the network. To explain this a bit
more detailed we have to look at the topology of an L<AnyEvent::MP>
network. The topology is called a I<fully connected mesh>, here an example
with 4 nodes:

   N1--N2
   | \/ |
   | /\ |
   N3--N4

Now imagine another I<node> C<N5>. wants to connect itself to that network:

   N1--N2
   | \/ |    N5
   | /\ |
   N3--N4

The new node needs to know the I<binds> of all nodes already
connected. Exactly this is what the I<seeds> are for: Let's assume that
the new node (C<N5>) uses the TCP address of the node C<N2> as seed.  This
cuases it to connect to C<N2>:

   N1--N2____
   | \/ |    N5
   | /\ |
   N3--N4

C<N2> then tells C<N5> about the I<binds> of the other nodes it is
connected to, and C<N5> creates the rest of the connections:

    /--------\
   N1--N2____|
   | \/ |    N5
   | /\ |   /|
   N3--N4--- |
    \________/

All done: C<N5> is now happily connected to the rest of the network.

=head3 Setting Up The Profiles

Ok, so much to the profile. Now let's setup the C<eg_simple_receiver>
I<profile> for later use. For the receiver we just give the receiver a
I<bind>:

   aemp profile eg_simple_receiver setbinds localhost:12266

We use C<localhost> in the example, but in the real world, you usually
want to use the "real" IP address of your node, so hosts can connect to
it. Of course, you can specify many binds, and it is also perfectly useful
to run multiple nodes on the same host. Just keep in mind that other nodes
will try to I<connect> to those addresses, and this better succeeds if you
want your network to be in good working conditions.

While we are at it, we setup the I<profile> for the sender in the
second part of this example, too. We will call the sender I<profile>
C<eg_simple_sender>. For the sender we set up a I<seed> pointing to the
receiver:

   aemp profile eg_simple_sender setseeds localhost:12266
   aemp profile eg_simple_sender setbinds

You might wonder why we setup I<binds> to be empty here: actually, the the
I<fully> in the I<fully connected mesh> is not the complete truth: If you
don't configure any I<binds> for a node profile it will parse and try to
resolve the node ID to find addresses to bind to. In this case we pretend
that we do not want this and epxlicitly specify an empty binds list, so
the node will not actually listen on any TCP ports.

Nodes without listeners will not be able to send messages to other nodes
without listeners, but they can still talk to all other nodes. For this
example, as well as in many cases in the real world, we can live with this
restriction, and this makes it easier to avoid DNS (assuming your setup is
broken, eliminating one potential problem :).

Whee, setting up nodes can be complicated at first, but you only have to
do it once per network, and you can leave this boring task to the admins
or end-users that want to use your stuff :)

=head3 Registering The Receiver

Coming back to our example, we have now introduced the basic purpose of
L<AnyEvent::MP::Global> and C<initialise_node> and its use of profiles. We
also set up our profiles for later use and now we will finally continue
talking about the receiver.

Let's look at the next line(s):

   my $port = port;
   AnyEvent::MP::Global::register $port, "eg_receivers";

The C<port> function has already been discussed. It simply creates a new
I<port> and returns the I<port ID>. The C<register> function, however,
is new:  The first argument is the I<port ID> that we want to add to a
I<global group>, and its second argument is the name of that I<global
group>.

You can choose the name of such a I<global group> freely (prefixing your
package name is highly recommended!). The purpose of such a group is to
store a set of I<port IDs>. This set is made available throughout the
whole L<AnyEvent::MP> network, so that each node can see which ports
belong to that group.

Later we will see how the sender looks for the ports in this I<global
group> to send messages to them.

The last step in the example is to set up a receiver callback for those
messages, just as was discussed in the first example. We again match
for the tag C<test>. The difference is that this time we don't exit the
application after receiving the first message. Instead we continue to wait
for new messages indefinitely.

=head2 The Sender

Ok, now let's take a look at the sender code:

   use AnyEvent;
   use AnyEvent::MP;
   use AnyEvent::MP::Global;

   initialise_node "eg_simple_sender";

   my $find_timer =
      AnyEvent->timer (after => 0, interval => 1, cb => sub {
         my $ports = AnyEvent::MP::Global::find "eg_receivers"
            or return;

         snd $_, test => time
            for @$ports;
      });

   AnyEvent->condvar->recv;

It's even less code. The C<initialise_node> serves the same purpose as in
the receiver, we just specify a different profile, the profile we set up
without the binds.

Next we set up a timer that repeatedly (every second) calls this chunk of
code:

   my $ports = AnyEvent::MP::Global::find "eg_receivers"
      or return;

   snd $_, test => time
      for @$ports;

The only new function here is the C<find> function of
L<AnyEvent::MP::Global>. It searches in the global group named
C<eg_receivers> for ports. If none are found, it returns C<undef>, which
makes our code return instantly and wait for the next round, as nobody is
interested in our message.

As soon as the receiver application has connected and the information
about the newly added port in the receiver has propagated to the sender
node, C<find> returns an array reference that contains the I<port ID> of
the receiver I<port(s)>.

We then just send a message with a tag and the current time to every
I<port> in the global group.

=head3 Multiple Receivers

You can even run multiple receivers - the only problem is that they will
use the same node ID. To avoid this problem, you can either not specify a
profile name at all and rely on DNS and your POSIX node name, or you can
use a special feature called "anonymous nodes":

   aemp profile eg_simple_receiver setnodeid anon/

The special name C<anon/> will be replaced by a random string each time
the node starts. This way you can start many receivers (they do not bind
on a TCP port, so cnanot collide with each other), and all of them will
receive the central time signal.

That's all for now - next time we will teach you about monitoring by
writing a simple chat client and server :)

=head1 SEE ALSO

L<AnyEvent>

L<AnyEvent::Handle>

L<AnyEvent::MP>

L<AnyEvent::MP::Global>

=head1 AUTHOR

  Robin Redeker <elmex@ta-sa.org>

