NAME#
Proc::Q - Queue up and run a herd of Procs
SYNOPSIS#
use Proc::Q; # Run 26 procs; each receiving stuff on STDIN and putting stuff out # to STDOUT, as well as sleeping for increasingly long periods of # time. The timeout of 3 seconds will kill all the procs that sleep # longer than that. my @stuff = 'a'..'z'; my $proc-chan = proc-q @stuff.map({«perl6 -e "print '$_' ~ \$*IN.slurp; sleep $($++/5)"»}), tags => @stuff.map('Letter ' ~ *), in => @stuff.map(*.uc), timeout => 3; react whenever $proc-chan { say "Got a result for {.tag}: STDOUT: {.out}" ~ (". Killed due to timeout" if .killed) } # OUTPUT: # Got a result for Letter a: STDOUT: aA # Got a result for Letter b: STDOUT: bB # Got a result for Letter c: STDOUT: cC # Got a result for Letter d: STDOUT: dD # Got a result for Letter e: STDOUT: eE # Got a result for Letter f: STDOUT: fF # Got a result for Letter g: STDOUT: gG # Got a result for Letter h: STDOUT: hH # Got a result for Letter i: STDOUT: iI # Got a result for Letter j: STDOUT: jJ # Got a result for Letter k: STDOUT: kK # Got a result for Letter l: STDOUT: lL # Got a result for Letter m: STDOUT: mM # Got a result for Letter n: STDOUT: nN # Got a result for Letter o: STDOUT: oO. Killed due to timeout # Got a result for Letter p: STDOUT: pP. Killed due to timeout # Got a result for Letter s: STDOUT: sS. Killed due to timeout # Got a result for Letter t: STDOUT: tT. Killed due to timeout # Got a result for Letter v: STDOUT: vV. Killed due to timeout # Got a result for Letter w: STDOUT: wW. Killed due to timeout # Got a result for Letter q: STDOUT: qQ. Killed due to timeout # Got a result for Letter r: STDOUT: rR. Killed due to timeout # Got a result for Letter u: STDOUT: uU. Killed due to timeout # Got a result for Letter x: STDOUT: xX. Killed due to timeout # Got a result for Letter y: STDOUT: yY. Killed due to timeout # Got a result for Letter z: STDOUT: zZ. Killed due to timeout
DESCRIPTION#
Requires Rakudo 2017.06 or newer.
Got a bunch of Procs
you want to queue up and run, preferably with some timeout for Procs that get stuck? Well, good news!
EXPORTED SUBROUTINES AND TYPES#
proc-q#
Defined as:
sub proc-q( +@commands where .so && .all ~~ List & .so, :@tags where .elems == @commands = @commands, :@in where { .elems == @commands|0 and all .map: {$_ ~~ Cool:D|Blob:D|Nil or $_ === Any} } = (Nil xx @commands).List, Numeric :$timeout where .DEFINITE.not || $_ > 0, UInt:D :$batch where .so = 8, :$out where Bool:D|'bin' = True, :$err where Bool:D|'bin' = True, Bool:D :$merge where .not | .so & ( $out & $err & ( ($err eq 'bin' & $out eq 'bin') | ($err ne 'bin' & $out ne 'bin'))) = False, --> Channel:D )
See SYNOPSIS for sample use.
Returns a Channel
of Proc::Q::Res
objects. Batches the @commands
in batches of $batch
and runs those via in parallel, optionally feeding STDIN with corresponding data from @in
, as well as capturing STDOUT/STDERR, and killing the process after $timeout
, if specified.
Arguments are as follows:
+@commands#
A list of lists, where each of inner lists is a list of arguments to Proc::Async.new
. You do not need to specify the :w
argument, and if you do, its value will be ignored.
Must have at least one list of commands inside @commands
.
:@tags#
To make it possible to match the input with the output, you can tag
each of the commands in @commands
by specifying the value via @tags
argument at the same index as the command is at. The given tag will be available via .tag
method of the Proc::Q::Res
object responsible.
Any object can be used as a tag. If <:@tags> is provided, it must have the same number of elements as +@commands
argument. If it's not provided, it defaults to @commands
.
:@in#
Optionally, you can send stuff to STDIN of your procs, by giving a Blob
or Str
in :@in
arg at the same index as the the index of the command for that proc in @commands
. If specified, the number of elements in @in
must be the same as number of elements in @commands
. Specify undefined value to avoid sending STDIN to a particular proc.
TIP: is your queue hanging for some reason? Ensure the procs you're running arent's sitting and waiting for STDIN. Try passing an empty strings in :@in
.
:$batch#
Takes a positive Int
. Defaults to 8
. Specifies how many @commands
to run at the same time.
:$timeout#
By default is not specified.
Takes a positive Numeric
specifying the number of seconds after which a proc should be killed, if it did not complete yet. Timer starts ticking once the proc is .ready
. The process is killed with SIGTERM
signal and if after 1 second it's still alive, it gets another kill with SIGSEGV
.
:$out#
Defaults to True
.
If set to True
or string 'bin'
, the routine will capture STDOUT from the procs, and make it available in .out
method of Proc::Q::Res
object. If set to string <'bin'>, the output will be captured in binary and .out
method will contain a Blob
instead of Str
.
:$err#
Same as :$out
except as applied to procs' STDERR.
:$merge#
Defaults to False
.
If set to True
, both :$err
and :$out
must be set to True
or both set to string 'bin'
.
If set to True
, the .merged
method will contain the merged output of STDOUT and STDERR (so it'll be a Str
or, if the :$out
/:$err
arei set to 'bin'
, a Blob
).
Note that there's no order guarantee. Output from a proc sent to STDERR after output to STDOUT, might end up before STDOUT's data in .merged
object.
Proc::Q::Res#
Each of the item sent to the Channel
from proc-q
routine will be a Proc::Q::Res
object (technically, it might also be an Exception
object if something explodes while trying to launch and wait for a proc, but it's of the "should never happen" variety; the Exception
will be the reason why stuff exploded).
While the @commands
to be executed will be batched in :$batch
items, the order within batches is not guaranteed. Use :@tags
to match the Proc::Q::Res
to the input commands.
The Proc::Q::Res
type contains information about the proc that was ran and provides these methods:
.tag#
The same object that was given as a tag via :@tags
argument (by default, the command from @commands
that was executed). The purpose of the .tag
is to match this Proc::Q::Res
object to the proc you ran.
.out#
Contains a Stringy
with STDOUT of the proc if :$out
argument to proc-q
is set to a true value.
.err#
Contains a Stringy
with STDERR of the proc if :$err
argument to proc-q
is set to a true value.
.merged#
Contains a Stringy
with merged STDOUT and STDERR of the proc if :$merge
argument to proc-q
is set to a true value. Note that even when :$merge
is in use, the .out
and .err
methods will contain the separated streams.
.exitcode#
Contains the exit code of the executed proc.
.killed#
A Bool:D
that is True
if this proc was killed due to the :$timeout
. More precisely, this is an indication that the timeout expired and the kill code started to run. It is possible for a proc to successfully complete in this small window opportunity between the attribute being set and the signal from .kill
being received by the process.
AUTHOR#
Zoffix Znet
COPYRIGHT AND LICENSE#
Copyright 2017 - 2018 Zoffix Znet
Copyright 2019 - 2022 Raku Community
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.