… | |
… | |
528 | This basically means "monitor $port and kill me when it crashes". And a |
528 | This basically means "monitor $port and kill me when it crashes". And a |
529 | "normal" kill does not count as a crash. This way you can easily link |
529 | "normal" kill does not count as a crash. This way you can easily link |
530 | ports together and make them crash together on errors (but allow you to |
530 | ports together and make them crash together on errors (but allow you to |
531 | remove a port silently). |
531 | remove a port silently). |
532 | |
532 | |
|
|
533 | =head3 Port Context |
|
|
534 | |
|
|
535 | When code runs in an environment where C<$SELF> contains its own port ID |
|
|
536 | and exceptions will be caught, it is said to run in a port context. |
|
|
537 | |
|
|
538 | Since AnyEvent::MP is event-based, it is not uncommon to register |
|
|
539 | callbacks from C<rcv> handlers. As example, assume that the port receive |
|
|
540 | handler wants to C<die> a second later, using C<after>: |
|
|
541 | |
|
|
542 | my $port = port { |
|
|
543 | after 1, sub { die "oops" }; |
|
|
544 | }; |
|
|
545 | |
|
|
546 | Then you will find it does not work - when the after callback is executed, |
|
|
547 | it does not run in port context anymore, so exceptions will not be caught. |
|
|
548 | |
|
|
549 | For these cases, AnyEvent::MP exports a special "close constructor" called |
|
|
550 | C<psub>, which works just like perl's builtin C<sub>: |
|
|
551 | |
|
|
552 | my $port = port { |
|
|
553 | after 1, psub { die "oops" }; |
|
|
554 | }; |
|
|
555 | |
|
|
556 | C<psub> stores C<$SELF> and returns a code reference. When the code |
|
|
557 | reference is invoked, it will run the code block within the context of |
|
|
558 | that port, so exception handling once more works as expected. |
|
|
559 | |
533 | =head3 Network Errors and the AEMP Guarantee |
560 | =head3 Network Errors and the AEMP Guarantee |
534 | |
561 | |
535 | I mentioned another important source of monitoring failures: network |
562 | I mentioned another important source of monitoring failures: network |
536 | problems. When a node loses connection to another node, it will invoke all |
563 | problems. When a node loses connection to another node, it will invoke all |
537 | monitoring actions as if the port was killed, even if it is possible that |
564 | monitoring actions as if the port was killed, even if it is possible that |
… | |
… | |
695 | mon $server, $client; |
722 | mon $server, $client; |
696 | } |
723 | } |
697 | |
724 | |
698 | server_connect; |
725 | server_connect; |
699 | |
726 | |
700 | my $w = AnyEvent->io (fh => *STDIN, poll => 'r', cb => sub { |
727 | my $w = AnyEvent->io (fh => 0, poll => 'r', cb => sub { |
701 | chomp (my $line = <STDIN>); |
728 | chomp (my $line = <STDIN>); |
702 | print "> "; |
729 | print "> "; |
703 | snd $server, privmsg => $nick, $line |
730 | snd $server, privmsg => $nick, $line |
704 | if $server; |
731 | if $server; |
705 | }); |
732 | }); |
… | |
… | |
785 | message, it should probably monitor itself, and the client should not try |
812 | message, it should probably monitor itself, and the client should not try |
786 | to send any messages unless a server is actually connected. |
813 | to send any messages unless a server is actually connected. |
787 | |
814 | |
788 | =head1 PART 3: TIMTOWTDI: Virtual Connections |
815 | =head1 PART 3: TIMTOWTDI: Virtual Connections |
789 | |
816 | |
|
|
817 | The chat system developed in the previous sections is very "traditional" |
|
|
818 | in a way: you start some server(s) and some clients statically and they |
|
|
819 | start talking to each other. |
|
|
820 | |
|
|
821 | Sometimes applications work more like "services": They can run on almost |
|
|
822 | any node and talks to itself on other nodes. The L<AnyEvent::MP::Global> |
|
|
823 | service for example monitors nodes joining the network and starts itself |
|
|
824 | automatically on other nodes (if it isn't running already). |
|
|
825 | |
|
|
826 | A good way to design such applications is to put them into a module and |
|
|
827 | create "virtual connections" to other nodes - we call this the "bridge |
|
|
828 | head" method, because you start by creating a remote port (the bridge |
|
|
829 | head) and from that you start to bootstrap your application. |
|
|
830 | |
|
|
831 | Since that sounds rather theoretical, let's redesign the chat server and |
|
|
832 | client using this design method. |
|
|
833 | |
|
|
834 | Here is the server: |
|
|
835 | |
|
|
836 | use common::sense; |
|
|
837 | use AnyEvent::MP; |
|
|
838 | use AnyEvent::MP::Global; |
|
|
839 | |
|
|
840 | configure; |
|
|
841 | |
|
|
842 | AnyEvent::MP::Global::register $NODE, "eg_chat_server2"; |
|
|
843 | |
|
|
844 | my %clients; |
|
|
845 | |
|
|
846 | sub msg { |
|
|
847 | print "relaying: $_[0]\n"; |
|
|
848 | snd $_, $_[0] |
|
|
849 | for values %clients; |
|
|
850 | } |
|
|
851 | |
|
|
852 | sub client_connect { |
|
|
853 | my ($client, $nick) = @_; |
|
|
854 | |
|
|
855 | mon $client; |
|
|
856 | mon $client, sub { |
|
|
857 | delete $clients{$client}; |
|
|
858 | msg "$nick (quits, @_)"; |
|
|
859 | }; |
|
|
860 | |
|
|
861 | $clients{$client} = $client; |
|
|
862 | |
|
|
863 | msg "$nick (joins)"; |
|
|
864 | |
|
|
865 | rcv $SELF, sub { msg "$nick: $_[0]" }; |
|
|
866 | } |
|
|
867 | |
|
|
868 | warn "server ready.\n"; |
|
|
869 | |
|
|
870 | AnyEvent->condvar->recv; |
|
|
871 | |
|
|
872 | It starts not much different, except that this time, we register the node |
|
|
873 | port and not any special port - the clients only want to know which node |
|
|
874 | the server should be running, and in fact, they could also sue some kind |
|
|
875 | of election mechanism or similar. |
|
|
876 | |
|
|
877 | The interesting change is that no port is created - the server is all |
|
|
878 | code, and does nothing. All it does is define a function C<client_connect> |
|
|
879 | that expects a client port and a nick as arguments. It then monitors the |
|
|
880 | client port and binds a receive callback on C<$SELF> that expects messages |
|
|
881 | to broadcast to all clients. |
|
|
882 | |
|
|
883 | The two C<mon> calls are a bit tricky - the first C<mon> is a shorthand |
|
|
884 | for C<mon $client, $SELF>. The second does the normal "client has gone |
|
|
885 | away" clean-up action. Both could actually be rolled into one C<mon> |
|
|
886 | action. |
|
|
887 | |
|
|
888 | C<$SELF> is a good hint that something interetsing is going on. And |
|
|
889 | indeed, when looking at the client, there is a new function, C<spawn>: |
|
|
890 | |
|
|
891 | use common::sense; |
|
|
892 | use AnyEvent::MP; |
|
|
893 | use AnyEvent::MP::Global; |
|
|
894 | |
|
|
895 | my $nick = shift; |
|
|
896 | |
|
|
897 | configure; |
|
|
898 | |
|
|
899 | $| = 1; |
|
|
900 | |
|
|
901 | my $port = port; |
|
|
902 | |
|
|
903 | my ($client, $server); |
|
|
904 | |
|
|
905 | sub server_connect { |
|
|
906 | my $servernodes = AnyEvent::MP::Global::find "eg_chat_server2" |
|
|
907 | or return after 1, \&server_connect; |
|
|
908 | |
|
|
909 | print "\rconnecting...\n"; |
|
|
910 | |
|
|
911 | $client = port { print "\r \r@_\n> " }; |
|
|
912 | mon $client, sub { |
|
|
913 | print "\rdisconnected @_\n"; |
|
|
914 | &server_connect; |
|
|
915 | }; |
|
|
916 | |
|
|
917 | $server = spawn $servernodes->[0], "::client_connect", $client, $nick; |
|
|
918 | mon $server, $client; |
|
|
919 | } |
|
|
920 | |
|
|
921 | server_connect; |
|
|
922 | |
|
|
923 | my $w = AnyEvent->io (fh => 0, poll => 'r', cb => sub { |
|
|
924 | chomp (my $line = <STDIN>); |
|
|
925 | print "> "; |
|
|
926 | snd $server, $line |
|
|
927 | if $server; |
|
|
928 | }); |
|
|
929 | |
|
|
930 | print "> "; |
|
|
931 | AnyEvent->condvar->recv; |
|
|
932 | |
|
|
933 | The client is quite similar to the previous one, but instead of contacting |
|
|
934 | the server port (which no longer exists), it C<spawn>s a new port on the |
|
|
935 | server I<node>: |
|
|
936 | |
|
|
937 | $server = spawn $servernodes->[0], "::client_connect", $client, $nick; |
|
|
938 | mon $server, $client; |
|
|
939 | |
|
|
940 | And of course immediately monitors it. The C<spawn> function creates a new |
|
|
941 | port on a remote node and returns its port ID. After creating the port it |
|
|
942 | calls a function on the remote node, passing any remaining arguments to |
|
|
943 | it, and - most importantly - within the context of the new port. The init |
|
|
944 | function can reside in a module (actually it normally I<should> reside |
|
|
945 | in a module) - AnyEvent::MP will automatically load the module if the |
|
|
946 | function isn't defined. |
|
|
947 | |
|
|
948 | The C<spawn> function returns immediately, which means you can immediately |
|
|
949 | send messages to the port, long before the remote node has even heard |
|
|
950 | of our request to create a port on it. In fact, the remote node might |
|
|
951 | not even be running. Despite these troubling facts, everything should |
|
|
952 | work just fine: if the node isn't running (or the init function throws an |
|
|
953 | exception), then the monitor will trigger because the port doesn't exist. |
|
|
954 | |
|
|
955 | If the spawn message gets delivered, but the monitoring message is not |
|
|
956 | because of network problems (monitoring, after all, is implemented by |
|
|
957 | passing a message, and messages can get lost), then this connection loss |
|
|
958 | will eventually trigger the monitoring action. On the remote node (which |
|
|
959 | reciprocally monitors the client) the port will also be cleaned up on |
|
|
960 | connection loss. When the node comes up and our monitoring message can be |
|
|
961 | delivered it will instantly fail because the port has been cleaned up in |
|
|
962 | the meantime. |
|
|
963 | |
|
|
964 | If your head is spinning by now, that's fine - just keep in mind, after |
|
|
965 | creating a port, monitor "the other side" from it, and all will be cleaned |
|
|
966 | up just fine. |
|
|
967 | |
|
|
968 | =head1 PART 4: Services |
|
|
969 | |
790 | #TODO |
970 | #TODO |
791 | |
971 | |
792 | =head1 SEE ALSO |
972 | =head1 SEE ALSO |
793 | |
973 | |
|
|
974 | L<AnyEvent::MP> |
|
|
975 | |
|
|
976 | L<AnyEvent::MP::Global> |
|
|
977 | |
794 | L<AnyEvent> |
978 | L<AnyEvent> |
795 | |
|
|
796 | L<AnyEvent::Handle> |
|
|
797 | |
|
|
798 | L<AnyEvent::MP> |
|
|
799 | |
|
|
800 | L<AnyEvent::MP::Global> |
|
|
801 | |
979 | |
802 | =head1 AUTHOR |
980 | =head1 AUTHOR |
803 | |
981 | |
804 | Robin Redeker <elmex@ta-sa.org> |
982 | Robin Redeker <elmex@ta-sa.org> |
805 | Marc Lehmann <schmorp@schmorp.de> |
983 | Marc Lehmann <schmorp@schmorp.de> |