MojoX::Run - asynchronous external command and subroutine execution for Mojo
# create async executor SINGLETON object my $mojox_run = MojoX::Run->singleton(); # simple usage my $pid = $mojox_run->spawn( cmd => "ping -W 2 -c 5 host.example.org", exit_cb => sub { my ($pid, $res) = @_; print "Ping finished with exit status $res->{exit_val}.\n"; print "\tSTDOUT:\n$res->{stdout}\n"; print "\tSTDERR:\n$res->{stderr}\n"; } ); # check for injuries unless ($pid) { print "Command startup failed: ", $mojox_run->error(), "\n"; } # more complex example... my $pid2 = $mojox_run->spawn( cmd => 'ping -W 2 -c 5 host.example.org', stdin_cb => sub { my ($pid, $chunk) = @_; print "STDOUT $pid: '$chunk'\n" }, # ignore stderr stderr_cb => sub {}, exit_cb => sub { my ($pid, $res) = @_; print "Process $res->{cmd} [pid: $pid] finished after $res->{time_duration_exec} second(s).\n"; print "Exit status: $res->{exit_status}"; print " by signal $res->{exit_signal}" if ($res->{exit_signal}); print " with coredump." if ($res->{exit_core}); print "\n"; } ); # even fancier usage: spawn coderef my $pid3 = $mojox_run->spawn( cmd => sub { for (my $i = 0; $i < 10; $i++) { if (rand() > 0.5) { print STDERR rand(), "\n" } else { print rand(), "\n"; } sleep int(rand(10)); } exit (rand() > 0.5) ? 0 : 1; }, exit_cb => { print "Sub exited with $res->{exit_status}, STDOUT: $res->{stdout}\n"; }, );
Object instance of this class takes over SIGCHLD signal handler. You have been warned!
Alias for "singleton" method - object constructor always returns the same object instance.
This restriction is enforced becouse there can be only one active SIGCHLD signal handler per process. However this shouldn't be a problem becouse you can run multiple external processes simultaneously with MojoX::Run :)
my $mojox_run = MojoX::Run->singleton();
Returns singleton object instance of MojoX::Run. Singleton object uses Mojo's Mojo::IOLoop singleton instance. This is probably what you want instead of creating your own private instance.
my $err = $mojox_run->error();
Returns last error.
my $pid = $mojox_run->spawn(%opt);
Spawns new subprocess. The following options are supported:
Command to be started. Command can be simple scalar, array reference or perl CODE reference if you want to custom perl subroutine asynchronously.
Code that will be invoked when data were read from processes's stdout. If omitted, stdout output will be returned as argument to exit_cb. Example:
stdout_cb => sub { my ($pid, $data) = @_; print "Process $pid stdout: $data"; }
Code that will be invoked when data were read from processes's stderr. If omitted, stderr output will be returned as argument to exit_cb. Example:
stderr_cb => sub { my ($pid, $data) = @_; print "Process $pid stderr: $data"; }
Code that will be invoked when data wrote to process's stdin were flushed. Example:
stdin_cb => sub { my ($pid) = @_; print "Process $pid: stdin was flushed."; }
Code to be invoked after process exits and all handles have been flushed. Function is called with 2 arguments: Process identifier (pid) and result structure. Example:
exit_cb => sub { my ($pid, $res) = @_; print "Process $pid exited\n"; print "Execution error: $res->{error}\n" if (defined $res->{error}); print "Exit status: $pid->{exit_status}\n"; print "Killed by signal $pid->{exit_signal}\n" if ($res->{exit_signal}); print "Process dumped core.\n" if (res->{exit_core}); print "Process was started at: $res->{time_started}\n"; print "Process exited at $res->{time_stopped}\n"; print "Process execution duration: $res->{time_duration_exec}\n"; print "Execution duration: $res->{time_duration_total}\n"; print "Process stdout: $res->{stdout}\n"; print "Process stderr: $res->{stderr}\n"; }
If set to positive non-zero value, process will be killed after specified timeout of seconds. Timeout accuracy depends on IOLoop's timeout() value (Default is 0.25 seconds).
Returns non-zero process identifier (pid) on success, otherwise 0 and sets error.
my $code = sub { return { a => 1, b => 2} }; my $pid = $mojox_run->spawn_sub( $code, exit_cb => sub { my ($pid, $result, $exception) = @_; } );
Spawns new subprocess in which $code subroutine will be executed. Return value of subroutine will be delivered to exit_cb callback.
The following options are supported:
exit_cb => sub { my ($pid, $result, $exception) = @_; if ($exception) { print "Horrible exception accoured while executing subroutine: $exception"; return; } # result is always arrayref, becouse subs can return list values! print "Got async sub result: ", Dumper($result), "\n"; }
If set to positive non-zero value, process will be killed after specified timeout of seconds. Timeout accuracy depends on IOLoop's timeout() value.
$mojox_run->stdin_write($pid, $data [, $cb]);
Writes $data to stdin of process $pid if process still has opened stdin. If $cb is defined code reference it will invoke it when data has been written. If $cb is omitted stdin_cb will be invoked if is set for process $pid.
Returns 1 on success, otherwise 0 and sets error.
# set $mojox_run->stdout_cb($pid, $cb); # get my $cb = $mojox_run->stdout_cb($pid);
If called without $cb argument returns stdout callback for process $pid, otherwise sets stdout callback. If $cb is undefined, removes callback.
Returns undef on error and sets error message.
# set $mojox_run->stderr_cb($pid, $cb); # get $cb = $mojox_run->stderr_cb($pid);
If called without $cb argument returns stderr callback for process $pid, otherwise sets stderr callback. If $cb is undefined, removes callback.
# set $mojox_run->stdin_cb($pid, $cb); # get $mojox_run->stdin_cb($pid);
If called without $cb argument returns stdin callback for process $pid, otherwise sets stdin callback. If $cb is undefined, removes callback.
$mojox_run->stdin_close($pid);
Closes stdin handle to specified process. You need to explicitly close stdin if spawned program doesn't exit until it's stdin is not closed.
# just get it $buf = $mojox_run->stdout_buf($pid); # get and drain $buf = $mojox_run->stdout_buf($pid, 1);
Returns contents of stdout buffer for process $pid on success, otherwise undef.
Internal buffer is cleared if invoked with non-zero second argument.
$buf = $mojox_run->stdout_buf_clear($pid);
Clears stdout buffer for process $pid. Returns string containing buffer contents on success, otherwise undef.
# just get it $buf = $mojox_run->stderr_buf($pid); # get and drain $buf = $mojox_run->stderr_buf($pid, 1);
Returns contents of stderr buffer for process $pid on success, otherwise undef.
$buf = $mojox_run->stderr_buf_clear($pid);
Clears stderr buffer for process $pid. Returns empty string on success, otherwise undef.
$mojox_run->kill($pid [, $signal = 15]);
Kills process $pid with specified signal. Returns 1 on success, otherwise 0.
Gets or sets loglevel for private logger instance. See Mojo::Log for additional instructions.
Returns number of currently managed sub-processes.
$mojox_run->max_running($limit);
Returns currently set concurrently running subprocesses limit if called without arguments. If called with integer argument sets new limit of concurrently spawned external processes and returns old limit.
Value of 0 means that there is no limit.
# get $loop = $mojox_run->ioloop(); # set $mojox_run->ioloop($loop);
Returns currently used ioloop if called without arguments. Currently used IO loop if changed invoked with initialized Mojo::IOLoop argument - you better be sure what you're doing!
There seem to be problems on some OpenBSD, DragonFly and Solaris systems in conjunction with Mojo::IOLoop implementation. Error manifests itself with the following warning message:
Filehandle GEN3 opened only for input at /usr/libdata/perl5/i386-openbsd/5.10.1/IO/Handle.pm line 465.
IO::Handle's syswrite method is called by Mojo::IOLoop's _write, but there is no good reason to write to process stdout or stderr... I'm investigating, feel free to contact me regarding this issue.
"Brane F. Gracnar", <"bfg at frost.ath.cx">
<"bfg at frost.ath.cx">
Please report any bugs or feature requests to bug-mojox-run at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MojoX-Run. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
bug-mojox-run at rt.cpan.org
You can find documentation for this module with the perldoc command.
perldoc MojoX::Run
You can also look for information at:
RT: CPAN's request tracker
http://rt.cpan.org/NoAuth/Bugs.html?Dist=MojoX-Run
AnnoCPAN: Annotated CPAN documentation
http://annocpan.org/dist/MojoX-Run
CPAN Ratings
http://cpanratings.perl.org/d/MojoX-Run
Search CPAN
http://search.cpan.org/dist/MojoX-Run/
Source repository
https://github.com/bfg/mojox-run
This module was inspired by POE::Wheel::Run by Rocco Caputo; module includes patched version of IPC::Open3 from Perl distribution which allows perl coderef execution.
Copyright 2010-2011, Brane F. Gracnar.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
To install MojoX::Run, copy and paste the appropriate command in to your terminal.
cpanm
cpanm MojoX::Run
CPAN shell
perl -MCPAN -e shell install MojoX::Run
For more information on module installation, please visit the detailed CPAN module installation guide.