AnyEvent-Fork-RPC

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN


       use AnyEvent;
       use AnyEvent::Fork;
       use AnyEvent::Fork::RPC;

       my $done = AE::cv;

       my $rpc = AnyEvent::Fork
          ->new
          ->require ("MyWorker")
          ->AnyEvent::Fork::RPC::run ("MyWorker::run",
             on_error   => sub { warn "ERROR: $_[0]"; exit 1 },
             on_event   => sub { warn "$_[0] requests handled\n" },
             on_destroy => $done,
          );

       for my $id (1..6) {
          $rpc->(rmdir => "/tmp/somepath/$id", sub {
             $_[0]
                or warn "/tmp/somepath/$id: $_[1]\n";
          });
       }

       undef $rpc;

       $done->recv;

    The parent creates the process, queues a few rmdir's. It then forgets
    about the $rpc object, so that the child exits after it has handled the
    requests, and then it waits till the requests have been handled.

    The child is implemented using a separate module, "MyWorker", shown
    here:

       package MyWorker;

       my $count;

       sub run {
          my ($cmd, $path) = @_;

          AnyEvent::Fork::RPC::event ($count)
             unless ++$count % 3;

          my $status = $cmd eq "rmdir"  ? rmdir  $path
                     : $cmd eq "unlink" ? unlink $path
                     : die "fatal error, illegal command '$cmd'";

          $status or (0, "$!")
       }

       1

    The "run" function first sends a "progress" event every three calls, and
    then executes "rmdir" or "unlink", depending on the first parameter (or
    dies with a fatal error - obviously, you must never let this happen :).

    Eventually it returns the status value true if the command was
    successful, or the status value 0 and the stringified error message.

    On my system, running the first code fragment with the given MyWorker.pm
    in the current directory yields:

       /tmp/somepath/1: No such file or directory
       /tmp/somepath/2: No such file or directory
       3  requests handled
       /tmp/somepath/3: No such file or directory
       /tmp/somepath/4: No such file or directory
       /tmp/somepath/5: No such file or directory
       6  requests handled
       /tmp/somepath/6: No such file or directory

    Obviously, none of the directories I am trying to delete even exist.
    Also, the events and responses are processed in exactly the same order
    as they were created in the child, which is true for both synchronous
    and asynchronous backends.

    Note that the parentheses in the call to "AnyEvent::Fork::RPC::event"
    are not optional. That is because the function isn't defined when the
    code is compiled. You can make sure it is visible by pre-loading the
    correct backend module in the call to "require":

          ->require ("AnyEvent::Fork::RPC::Sync", "MyWorker")

    Since the backend module declares the "event" function, loading it first
    ensures that perl will correctly interpret calls to it.

    And as a final remark, there is a fine module on CPAN that can
    asynchronously "rmdir" and "unlink" and a lot more, and more efficiently
    than this example, namely IO::AIO.

   Example 1a: the same with the asynchronous backend
    This example only shows what needs to be changed to use the async
    backend instead. Doing this is not very useful, the purpose of this
    example is to show the minimum amount of change that is required to go
    from the synchronous to the asynchronous backend.

    To use the async backend in the previous example, you need to add the
    "async" parameter to the "AnyEvent::Fork::RPC::run" call:

          ->AnyEvent::Fork::RPC::run ("MyWorker::run",
             async      => 1,
             ...

    And since the function call protocol is now changed, you need to adopt
    "MyWorker::run" to the async API.

    First, you need to accept the extra initial $done callback:

       sub run {
          my ($done, $cmd, $path) = @_;

    And since a response is now generated when $done is called, as opposed
    to when the function returns, we need to call the $done function with
    the status:

          $done->($status or (0, "$!"));

    A few remarks are in order. First, it's quite pointless to use the async
    backend for this example - but it *is* possible. Second, you can call
    $done before or after returning from the function. Third, having both



( run in 0.809 second using v1.01-cache-2.11-cpan-b16cb0d3907 )