… | |
… | |
387 | Ok, so far, this works. In the real world, however, the person configuring |
387 | Ok, so far, this works. In the real world, however, the person configuring |
388 | your application to run on a specific network (the end user or network |
388 | your application to run on a specific network (the end user or network |
389 | administrator) is often different to the person coding the application. |
389 | administrator) is often different to the person coding the application. |
390 | |
390 | |
391 | Or to put it differently: the arguments passed to configure are usually |
391 | Or to put it differently: the arguments passed to configure are usually |
392 | provided not by the programmer, but by whoeever is deplying the program. |
392 | provided not by the programmer, but by whoever is deploying the program. |
393 | |
393 | |
394 | To make this easy, AnyEvent::MP supports a simple configuration database, |
394 | To make this easy, AnyEvent::MP supports a simple configuration database, |
395 | using profiles, which can be managed using the F<aemp> command-line |
395 | using profiles, which can be managed using the F<aemp> command-line |
396 | utility (yes, this section is about the advanced tinkering we mentioned |
396 | utility (yes, this section is about the advanced tinkering we mentioned |
397 | before). |
397 | before). |
… | |
… | |
533 | =head3 Network Errors and the AEMP Guarantee |
533 | =head3 Network Errors and the AEMP Guarantee |
534 | |
534 | |
535 | I mentioned another important source of monitoring failures: network |
535 | I mentioned another important source of monitoring failures: network |
536 | problems. When a node loses connection to another node, it will invoke all |
536 | 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 |
537 | monitoring actions as if the port was killed, even if it is possible that |
538 | the prot sitll lives happily on another node (not being able to talk to a |
538 | the port still lives happily on another node (not being able to talk to a |
539 | node means we have no clue what's going on with it, it could be crashed, |
539 | node means we have no clue what's going on with it, it could be crashed, |
540 | but also still running without knowing we lost the connection). |
540 | but also still running without knowing we lost the connection). |
541 | |
541 | |
542 | So another way to view monitors is "notify me when some of my messages |
542 | So another way to view monitors is "notify me when some of my messages |
543 | couldn't be delivered". AEMP has a guarantee about message delivery to a |
543 | couldn't be delivered". AEMP has a guarantee about message delivery to a |
544 | port: After starting a monitor, any message sent to a port will either |
544 | port: After starting a monitor, any message sent to a port will either |
545 | be delivered, or, when it is lost, any further messages will also be lost |
545 | be delivered, or, when it is lost, any further messages will also be lost |
546 | until the monitoring action is invoked. After that, further messgaes |
546 | until the monitoring action is invoked. After that, further messages |
547 | I<might> get delivered again. |
547 | I<might> get delivered again. |
548 | |
548 | |
549 | This doesn't sound like a very big guarantee, but it is kind of the best |
549 | This doesn't sound like a very big guarantee, but it is kind of the best |
550 | you can get whiel staying sane: Specifically, it means that there will |
550 | you can get while staying sane: Specifically, it means that there will |
551 | be no "wholes" in the message sequence: all messages sent are delivered |
551 | be no "holes" in the message sequence: all messages sent are delivered |
552 | in order, without any missing in between, and when some were lost, you |
552 | in order, without any missing in between, and when some were lost, you |
553 | I<will> be notified of that, so you can take recovery action. |
553 | I<will> be notified of that, so you can take recovery action. |
554 | |
554 | |
555 | =head3 Supervising |
555 | =head3 Supervising |
556 | |
556 | |
… | |
… | |
558 | I<more> stable? Well in fact, the goal is not really to make them more |
558 | I<more> stable? Well in fact, the goal is not really to make them more |
559 | stable, but to make them more resilient against actual errors and |
559 | stable, but to make them more resilient against actual errors and |
560 | crashes. And this is not done by crashing I<everything>, but by crashing |
560 | crashes. And this is not done by crashing I<everything>, but by crashing |
561 | everything except a supervisor. |
561 | everything except a supervisor. |
562 | |
562 | |
563 | A supervisor is simply some code that ensures that an applciation (or a |
563 | A supervisor is simply some code that ensures that an application (or a |
564 | part of it) is running, and if it crashes, is restarted properly. |
564 | part of it) is running, and if it crashes, is restarted properly. |
565 | |
565 | |
566 | To show how to do all this we will create a simple chat server that can |
566 | To show how to do all this we will create a simple chat server that can |
567 | handle many chat clients. Both server and clients can be killed and |
567 | handle many chat clients. Both server and clients can be killed and |
568 | restarted, and even crash, to some extent. |
568 | restarted, and even crash, to some extent. |
… | |
… | |
609 | |
609 | |
610 | warn "server ready.\n"; |
610 | warn "server ready.\n"; |
611 | |
611 | |
612 | AnyEvent->condvar->recv; |
612 | AnyEvent->condvar->recv; |
613 | |
613 | |
614 | Looks like a lot, but it is actually quite simple: after your usualy |
614 | Looks like a lot, but it is actually quite simple: after your usual |
615 | preamble (this time we use common sense), we define a helper function that |
615 | preamble (this time we use common sense), we define a helper function that |
616 | sends some message to every registered chat client: |
616 | sends some message to every registered chat client: |
617 | |
617 | |
618 | sub msg { |
618 | sub msg { |
619 | print "relaying: $_[0]\n"; |
619 | print "relaying: $_[0]\n"; |
… | |
… | |
652 | rcv $server, privmsg => sub { |
652 | rcv $server, privmsg => sub { |
653 | my ($nick, $msg) = @_; |
653 | my ($nick, $msg) = @_; |
654 | msg "$nick: $msg"; |
654 | msg "$nick: $msg"; |
655 | }; |
655 | }; |
656 | |
656 | |
657 | And finally, the server rgeisters itself in the server group, so that |
657 | And finally, the server registers itself in the server group, so that |
658 | clients can find it: |
658 | clients can find it: |
659 | |
659 | |
660 | AnyEvent::MP::Global::register $server, "eg_chat_server"; |
660 | AnyEvent::MP::Global::register $server, "eg_chat_server"; |
661 | |
661 | |
662 | Well, well... and where is this supervisor stuff? Well... we cheated, |
662 | Well, well... and where is this supervisor stuff? Well... we cheated, |
… | |
… | |
751 | |
751 | |
752 | The rest of the program deals with the boring details of actually invoking |
752 | The rest of the program deals with the boring details of actually invoking |
753 | the supervisor function to start the whole client process and handle the |
753 | the supervisor function to start the whole client process and handle the |
754 | actual terminal input, sending it to the server. |
754 | actual terminal input, sending it to the server. |
755 | |
755 | |
756 | You should now try to start the server and one or more clients in diferent |
756 | You should now try to start the server and one or more clients in different |
757 | terminal windows (and the seed node): |
757 | terminal windows (and the seed node): |
758 | |
758 | |
759 | perl eg/chat_client nick1 |
759 | perl eg/chat_client nick1 |
760 | perl eg/chat_client nick2 |
760 | perl eg/chat_client nick2 |
761 | perl eg/chat_server |
761 | perl eg/chat_server |