AnyEvent-Fork-RPC
view release on metacpan or search on metacpan
This serialiser (currently the default) concatenates length-prefixes octet
strings, and is the default. That means you can only pass (and return)
strings containing character codes 0-255.
The main advantages of this serialiser are the high speed and that it
doesn't need another module. The main disadvantage is that you are very
limited in what you can pass - only octet strings.
Implementation:
(
sub { pack "(w/a*)*", @_ },
sub { unpack "(w/a*)*", shift }
)
=item C<$AnyEvent::Fork::RPC::CBOR_XS_SERIALISER> - uses L<CBOR::XS>
This serialiser creates CBOR::XS arrays - you have to make sure the
L<CBOR::XS> module is installed for this serialiser to work. It can be
beneficial for sharing when you preload the L<CBOR::XS> module in a template
process.
L<CBOR::XS> is about as fast as the octet string serialiser, but supports
complex data structures (similar to JSON) and is faster than any of the
other serialisers. If you have the L<CBOR::XS> module available, it's the
best choice.
The encoder enables C<allow_sharing> (so this serialisation method can
encode cyclic and self-referencing data structures).
Implementation:
use CBOR::XS ();
(
sub { CBOR::XS::encode_cbor_sharing \@_ },
sub { @{ CBOR::XS::decode_cbor shift } }
)
=item C<$AnyEvent::Fork::RPC::JSON_SERIALISER> - uses L<JSON::XS> or L<JSON>
This serialiser creates JSON arrays - you have to make sure the L<JSON>
module is installed for this serialiser to work. It can be beneficial for
sharing when you preload the L<JSON> module in a template process.
L<JSON> (with L<JSON::XS> installed) is slower than the octet string
serialiser, but usually much faster than L<Storable>, unless big chunks of
binary data need to be transferred.
Implementation:
use JSON ();
(
sub { JSON::encode_json \@_ },
sub { @{ JSON::decode_json shift } }
)
=item C<$AnyEvent::Fork::RPC::STORABLE_SERIALISER> - L<Storable>
This serialiser uses L<Storable>, which means it has high chance of
serialising just about anything you throw at it, at the cost of having
very high overhead per operation. It also comes with perl. It should be
used when you need to serialise complex data structures.
Implementation:
use Storable ();
(
sub { Storable::freeze \@_ },
sub { @{ Storable::thaw shift } }
)
=item C<$AnyEvent::Fork::RPC::NSTORABLE_SERIALISER> - portable Storable
This serialiser also uses L<Storable>, but uses it's "network" format
to serialise data, which makes it possible to talk to different
perl binaries (for example, when talking to a process created with
L<AnyEvent::Fork::Remote>).
Implementation:
use Storable ();
(
sub { Storable::nfreeze \@_ },
sub { @{ Storable::thaw shift } }
)
=back
=item buflen => $bytes (default: C<512 - 16>)
The starting size of the read buffer for request and response data.
C<AnyEvent::Fork::RPC> ensures that the buffer for reeading request and
response data is large enough for at leats aingle request or response, and
will dynamically enlarge the buffer if needed.
While this ensures that memory is not overly wasted, it typically leads
to having to do one syscall per request, which can be inefficient in some
cases. In such cases, it can be beneficient to increase the buffer size to
hold more than one request.
=item buflen_req => $bytes (default: same as C<buflen>)
Overrides C<buflen> for request data (as read by the forked process).
=item buflen_res => $bytes (default: same as C<buflen>)
Overrides C<buflen> for response data (replies read by the parent process).
=back
See the examples section earlier in this document for some actual
examples.
=cut
our $STRING_SERIALISER = '(sub { pack "(w/a*)*", @_ }, sub { unpack "(w/a*)*", shift })';
our $CBOR_XS_SERIALISER = 'use CBOR::XS (); (sub { CBOR::XS::encode_cbor_sharing \@_ }, sub { @{ CBOR::XS::decode_cbor shift } })';
our $JSON_SERIALISER = 'use JSON (); (sub { JSON::encode_json \@_ }, sub { @{ JSON::decode_json shift } })';
our $STORABLE_SERIALISER = 'use Storable (); (sub { Storable::freeze \@_ }, sub { @{ Storable::thaw shift } })';
Note that these functions are typically not yet declared when code is
compiled into the child, because the backend module is only loaded when
you call C<run>, which is typically the last method you call on the fork
object.
Therefore, you either have to explicitly pre-load the right backend module
or mark calls to these functions as function calls, e.g.:
AnyEvent::Fork::RPC::event (0 => "five");
AnyEvent::Fork::RPC::event->(0 => "five");
&AnyEvent::Fork::RPC::flush;
=over 4
=item AnyEvent::Fork::RPC::event (...)
Send an event to the parent. Events are a bit like RPC calls made by the
child process to the parent, except that there is no notion of return
values.
See the examples section earlier in this document for some actual
examples.
Note: the event data, like any data send to the parent, might not be sent
immediatelly but queued for later sending, so there is no guarantee that
the event has been sent to the parent when the call returns - when you
e.g. exit directly after calling this function, the parent might never
receive the event. See the next function for a remedy.
=item $success = AnyEvent::Fork::RPC::flush ()
Synchronously wait and flush the reply data to the parent. Returns true on
success and false otherwise (i.e. when the reply data cannot be written at
all). Ignoring the success status is a common and healthy behaviour.
Only the "async" backend does something on C<flush> - the "sync" backend
is not buffering reply data and always returns true from this function.
Normally, reply data might or might not be written to the parent
immediatelly but is buffered. This can greatly improve performance and
efficiency, but sometimes can get in your way: for example. when you want
to send an error message just before exiting, or when you want to ensure
replies timely reach the parent before starting a long blocking operation.
In these cases, you can call this function to flush any outstanding reply
data to the parent. This is done blockingly, so no requests will be
handled and no event callbacks will be called.
For example, you could wrap your request function in a C<eval> block and
report the exception string back to the caller just before exiting:
sub req {
...
eval {
...
};
if ($@) {
AnyEvent::RPC::event (throw => "$@");
AnyEvent::RPC::flush ();
exit;
}
...
}
=back
=head2 PROCESS EXIT
If and when the child process exits depends on the backend and
configuration. Apart from explicit exits (e.g. by calling C<exit>) or
runtime conditions (uncaught exceptions, signals etc.), the backends exit
under these conditions:
=over 4
=item Synchronous Backend
The synchronous backend is very simple: when the process waits for another
request to arrive and the writing side (usually in the parent) is closed,
it will exit normally, i.e. as if your main program reached the end of the
file.
That means that if your parent process exits, the RPC process will usually
exit as well, either because it is idle anyway, or because it executes a
request. In the latter case, you will likely get an error when the RPc
process tries to send the results to the parent (because agruably, you
shouldn't exit your parent while there are still outstanding requests).
The process is usually quiescent when it happens, so it should rarely be a
problem, and C<END> handlers can be used to clean up.
=item Asynchronous Backend
For the asynchronous backend, things are more complicated: Whenever it
listens for another request by the parent, it might detect that the socket
was closed (e.g. because the parent exited). It will sotp listening for
new requests and instead try to write out any remaining data (if any) or
simply check whether the socket can be written to. After this, the RPC
process is effectively done - no new requests are incoming, no outstanding
request data can be written back.
Since chances are high that there are event watchers that the RPC server
knows nothing about (why else would one use the async backend if not for
the ability to register watchers?), the event loop would often happily
continue.
This is why the asynchronous backend explicitly calls C<CORE::exit> when
it is done (under other circumstances, such as when there is an I/O error
and there is outstanding data to write, it will log a fatal message via
L<AnyEvent::Log>, also causing the program to exit).
You can override this by specifying a function name to call via the C<done>
parameter instead.
=back
=head1 ADVANCED TOPICS
( run in 0.642 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )