Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like...
Transcript of Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like...
![Page 1: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/1.jpg)
Understanding react, supply, and whenever
Jonathan Worthington Edument
![Page 2: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/2.jpg)
Well, they're just...
![Page 3: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/3.jpg)
A mechanism for consuming zero or more asynchronous streams (often
called "reactive streams"), providing concurrency control though one-
message-at-a-time processing, automatically handling error and
completion propagation, and managing subscriptions, with the
option of producing a new stream of values as a result
![Page 4: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/4.jpg)
Any questions?
![Page 5: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/5.jpg)
Let's talk about for loops.
![Page 6: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/6.jpg)
for $fh.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Iterable data source
![Page 7: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/7.jpg)
for $fh.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Pull one value
Run the loop body
![Page 8: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/8.jpg)
for $fh.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Pull one value
Run the loop body
These happen in lockstep
![Page 9: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/9.jpg)
for $fh.lines -> $line { last if $line eq 'END'; say $line.split(' ')[0]; }
Pull one value
Run the loop body
These happen in lockstep
Lost interest? Just stop. GC eats iterator.
![Page 10: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/10.jpg)
for $fh.lines -> $line { last if $line eq 'END'; say $line.split(' ')[0]; }
Pull one value
Run the loop body
These happen in lockstep
Next statement runs after completion of the loop
Lost interest? Just stop. GC eats iterator.
![Page 11: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/11.jpg)
for $fh.lines -> $line { last if $line eq 'END'; say $line.split(' ')[0]; }
Pull one value
Run the loop body
These happen in lockstep
Next statement runs after completion of the loop
Synchronous programming
Lost interest? Just stop. GC eats iterator.
![Page 12: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/12.jpg)
Once we spot the iterator pattern, we can see its use in many situations...
Moving through a collection
Reading lines (lazily) from a file Reading rows from a database
Walking anything via. a generator
![Page 13: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/13.jpg)
So what about asynchronous programming?
![Page 14: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/14.jpg)
The idea of asynchronous streams, like iterators, captures so many things...
Output from sub-process handles
Packets arriving over a socket Ticks of a timer
User interface events Message queue messages Business/domain events
![Page 15: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/15.jpg)
Thought experiment:
What if we were to have a loop-like construct for asynchronous streams?
![Page 16: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/16.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Observable data source
![Page 17: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/17.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Subscribe to events
Run code on an event
![Page 18: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/18.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Subscribe to events
Run code on an event
Events occur any time, even on any thread, after subscription
![Page 19: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/19.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Subscribe to events
Run code on an event
Events occur any time, even on any thread, after subscription
Unsubscribe
![Page 20: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/20.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Subscribe to events
Run code on an event
Events occur any time, even on any thread, after subscription
Unsubscribe
Next statement...uhh...hmmm
![Page 21: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/21.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Subscribe to events
Run code on an event
Events occur any time, even on any thread, after subscription
Unsubscribe
Next statement...uhh...hmmm
Asynchronous programming
![Page 22: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/22.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Subscribe to events
Run code on an event
Events occur any time, even on any thread, after subscription
Unsubscribe
Next statement...uhh...hmmm
Asynchronous programming
We'll need a means of
concurrency control
![Page 23: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/23.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Subscribe to events
Run code on an event
Events occur any time, even on any thread, after subscription
Unsubscribe
Next statement...uhh...hmmm
Asynchronous programming
Could await the end of
the stream...
![Page 24: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/24.jpg)
??? $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
Subscribe to events
Run code on an event
Events occur any time, even on any thread, after subscription
Unsubscribe
Next statement...uhh...hmmm
Asynchronous programming
...but what if we want to
process many streams?
![Page 25: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/25.jpg)
In Perl 6, whenever is an asynchronous loop construct
Subscribes to the stream Runs the body on each event
Unsubscribes on last
whenever $proc.stdout.lines -> $line { last if $line ~~ /^END/; say $line.split(' ')[0]; }
![Page 26: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/26.jpg)
whenever must be used in combination with either
react or supply
![Page 27: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/27.jpg)
react whenever Supply.interval(1) -> $i { say $i %% 2 ?? "Tick" !! "Tock"; last if $i > 10; } A whenever subscribes, then execution continues
![Page 28: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/28.jpg)
react whenever Supply.interval(1) -> $i { say $i %% 2 ?? "Tick" !! "Tock"; last if $i > 10; }
Waits until whenever exits or the stream ends
![Page 29: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/29.jpg)
react { whenever Supply.interval(1) -> $i { say $i %% 2 ?? "Tick" !! "Tock"; last if $i > 10; } }
As with other statement prefixes, react takes a block or a statement
![Page 30: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/30.jpg)
react { whenever Supply.interval(1) -> $i { say $i %% 2 ?? "Tick" !! "Tock"; last if $i > 10; } # So we can add another whenever! }
As with other statement prefixes, react takes a block or a statement
![Page 31: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/31.jpg)
whenever sets up a subscription
react manages a set of subscriptions
![Page 32: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/32.jpg)
use Terminal::ANSIColor; unit sub MAIN(Str $program, *@args); react { my $proc = Proc::Async.new($program, @args); whenever $proc.stdout.lines { say colored($_, 'green'); } whenever $proc.stderr.lines { note colored($_, 'yellow'); } whenever $proc.start { exit .exitcode; } }
Run a process, color STDOUT green and STDERR yellow, pass on exit code
![Page 33: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/33.jpg)
A react terminates when there are no more subscriptions
Often, this allows us to eliminate a bunch of completion tracking logic
![Page 34: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/34.jpg)
# Run 4 test files at a time my $degree = 4; # Find the test files to run my @tests = dir('t').grep(/\.t$/); # And here comes the fun stuff... react { ... }
Run test files in parallel, envelope output
![Page 35: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/35.jpg)
# Run 4 test files at a time my $degree = 4; # Find the test files to run my @tests = dir('t').grep(/\.t$/); # And here comes the fun stuff... react { # Set off $degree tests at first run-one for 1..$degree; sub run-one { # Run one test, call run-one again when it ends, # thus maintaining $degree active tests at a time ... } }
Run test files in parallel, envelope output
![Page 36: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/36.jpg)
sub run-one { # Run one test, call run-one again when it ends, # thus maintaining $degree active tests at a time ... }
Run test files in parallel, envelope output
![Page 37: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/37.jpg)
sub run-one { # If there's no more tests, just return my $test = @tests.shift // return; # Otherwise, run the test and collect the output ... }
Run test files in parallel, envelope output
![Page 38: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/38.jpg)
sub run-one { # If there's no more tests, just return my $test = @tests.shift // return; # Otherwise, run test, collect, and send output my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever $proc.stdout.lines { push @output, "OUT: $_"; } whenever $proc.stderr.lines { push @output, "ERR: $_"; } whenever $proc.start { push @output, "EXIT: {.exitcode}"; say @output.join("\n"); ... } }
Run test files in parallel, envelope output
![Page 39: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/39.jpg)
sub run-one { # If there's no more tests, just return my $test = @tests.shift // return; # Otherwise, run test, collect, and send output my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever $proc.stdout.lines { push @output, "OUT: $_"; } whenever $proc.stderr.lines { push @output, "ERR: $_"; } whenever $proc.start { push @output, "EXIT: {.exitcode}"; say @output.join("\n"); # Since this test is done, trigger one more run-one(); } }
Run test files in parallel, envelope output
![Page 40: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/40.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever $proc.stdout.lines { push @output, "OUT: $_"; } whenever $proc.stderr.lines { push @output, "ERR: $_"; } whenever $proc.start { push @output, "EXIT: {.exitcode}"; say @output.join("\n"); run-one(); } } run-one for 1..$degree; }
Run test files in parallel, envelope output
![Page 41: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/41.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever $proc.stdout.lines { push @output, "OUT: $_"; } whenever $proc.stderr.lines { push @output, "ERR: $_"; } whenever $proc.start { push @output, "EXIT: {.exitcode}"; say @output.join("\n"); run-one(); } } run-one for 1..$degree; }
Run test files in parallel, envelope output
Each whenever registers its
subscription with the enclosing react...
![Page 42: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/42.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever $proc.stdout.lines { push @output, "OUT: $_"; } whenever $proc.stderr.lines { push @output, "ERR: $_"; } whenever $proc.start { push @output, "EXIT: {.exitcode}"; say @output.join("\n"); run-one(); } } run-one for 1..$degree; }
Run test files in parallel, envelope output
...so it can terminate when there are no
more active subscriptions
![Page 43: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/43.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever $proc.stdout.lines { push @output, "OUT: $_"; } whenever $proc.stderr.lines { push @output, "ERR: $_"; } whenever $proc.start { push @output, "EXIT: {.exitcode}"; say @output.join("\n"); run-one(); } } run-one for 1..$degree; }
Run test files in parallel, envelope output
Arrays are not threadsafe.
Concurrency control???
![Page 44: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/44.jpg)
A react processes one event at a time
So all state inside the react block is covered by this concurrency control
The setup phase - running the react
block to establish initial subscriptions - is considered as an initial event
![Page 45: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/45.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever $proc.stdout.lines { push @output, "OUT: $_"; } whenever $proc.stderr.lines { push @output, "ERR: $_"; } whenever $proc.start { push @output, "EXIT: {.exitcode}"; say @output.join("\n"); run-one(); } } run-one for 1..$degree; }
Can we factor out the enveloping part?
![Page 46: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/46.jpg)
One more thought experiment:
If react is like for, in so far as we process values and do side-effects,
then what is like map, where we produce a result sequence?
![Page 47: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/47.jpg)
In Perl 6, we call that a supply block
![Page 48: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/48.jpg)
sub envelope-process(Proc::Async $proc --> Supply) { supply { whenever $proc.stdout.lines { emit "OUT: $_"; } whenever $proc.stderr.lines { emit "ERR: $_"; } whenever $proc.start { emit "EXIT: {.exitcode}"; } } }
![Page 49: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/49.jpg)
Returns a Supply (the Perl 6 type for an asynchronous stream)
Runs the supply body each time that Supply is tapped (subscribed to)
Think of it like subscribing making a
new "instance"
![Page 50: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/50.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever envelope-process($proc) { push @output, $_; LAST { say @output.join("\n"); run-one(); } } } run-one for 1..$degree; }
Call the sub, subscribe to what it returns
![Page 51: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/51.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever envelope-process($proc) { push @output, $_; LAST { say @output.join("\n"); run-one(); } } } run-one for 1..$degree; }
LAST runs when the stream ends
![Page 52: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/52.jpg)
Final challenge:
How can we implement a timeout mechanism for hanging processes?
![Page 53: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/53.jpg)
# Exception type to throw if we time out. class X::Timeout is Exception {} sub timeout(Supply $source, Real $seconds --> Supply) { supply { # Pass on values. If $seconds have elapsed, # throw exception. ... } }
![Page 54: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/54.jpg)
# Exception type to throw if we time out. class X::Timeout is Exception {} sub timeout(Supply $source, Real $seconds --> Supply) { supply { # Pass on values. whenever $source { emit $_; } # If $seconds have elapsed, throw exception. ... } }
![Page 55: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/55.jpg)
# Exception type to throw if we time out. class X::Timeout is Exception {} sub timeout(Supply $source, Real $seconds --> Supply) { supply { # Pass on values. whenever $source { emit $_; } # If $seconds have elapsed, throw exception. whenever Promise.in($seconds) { die X::Timeout.new; } } }
![Page 56: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/56.jpg)
# Exception type to throw if we time out. class X::Timeout is Exception {} sub timeout(Supply $source, Real $seconds --> Supply) { supply { # Pass on values. whenever $source { emit $_; } # If $seconds have elapsed, throw exception. whenever Promise.in($seconds) { die X::Timeout.new; } } }
But we'll always wait
for the timeout?!
![Page 57: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/57.jpg)
# Exception type to throw if we time out. class X::Timeout is Exception {} sub timeout(Supply $source, Real $seconds --> Supply) { supply { # Pass on values. whenever $source { emit $_; # Use done to terminate the supply block LAST done; } # If $seconds have elapsed, throw exception. whenever Promise.in($seconds) { die X::Timeout.new; } } }
![Page 58: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/58.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever timeout(envelope-process($proc), 2) { push @output, $_; LAST { say @output.join("\n"); run-one(); } } } run-one for 1..$degree; }
Using timeout is easy...but where does the exception go?
![Page 59: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/59.jpg)
Unhandled exceptions cause all subscriptions to be closed
The exception is rethrown in the code
that triggered the react block
![Page 60: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/60.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever timeout(envelope-process($proc), 2) { push @output, $_; LAST { say @output.join("\n"); run-one(); } QUIT { when X::Timeout { $proc.kill; push @output, "TIMEOUT"; say @output.join("\n"); run-one(); } } } } run-one for 1..$degree; }
QUIT catches asynchronous exceptions
![Page 61: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/61.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever timeout(envelope-process($proc), 2) { push @output, $_; LAST { say @output.join("\n"); run-one(); } QUIT { when X::Timeout { $proc.kill; push @output, "TIMEOUT"; say @output.join("\n"); run-one(); } } } } run-one for 1..$degree; }
QUIT catches asynchronous exceptions
Looks like duplicated
code to me!
![Page 62: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/62.jpg)
react { sub run-one { my $test = @tests.shift // return; my $proc = Proc::Async.new('perl6', '-Ilib', $test); my @output = "FILE: $test"; whenever timeout(envelope-process($proc), 2) { push @output, $_; LAST handle-termination; QUIT { when X::Timeout { $proc.kill; push @output, "TIMEOUT"; handle-termination; } } } sub handle-termination() { say @output.join("\n"); run-one(); } } run-one for 1..$degree; }
Tidy up, and we're done
![Page 63: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/63.jpg)
In summary....
![Page 64: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/64.jpg)
whenever
Attaches to react or supply
![Page 65: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/65.jpg)
whenever
Attaches to react or supply
Side-effects New stream
![Page 66: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/66.jpg)
whenever
Attaches to react or supply
Side-effects New stream
Concurrency control Completion and error propagation
![Page 67: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/67.jpg)
whenever
Attaches to react or supply
Side-effects New stream
Works like a loop (last, next, LAST) End all subscriptions with done
Concurrency control Completion and error propagation
![Page 68: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/68.jpg)
Or, in other words...
![Page 69: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/69.jpg)
A mechanism for consuming zero or more asynchronous streams (often
called "reactive streams"), providing concurrency control though one-
message-at-a-time processing, automatically handling error and
completion propagation, and managing subscriptions, with the
option of producing a new stream of values as a result
![Page 70: Edumentjnthn.net/papers/2019-gpw-react-supply-whenever.pdfThe idea of asynchronous streams, like iterators, captures so many things... Output from sub-process handles Packets arriving](https://reader033.fdocuments.us/reader033/viewer/2022042309/5ed5a7de740631020e41cf44/html5/thumbnails/70.jpg)
Thank you!
Questions?