Day 19 - Cancellation
As a future is a first-class object that represents an ongoing operation or activity, it serves as an ideal place to interact with that activity. As well as waiting for success or failure of this operation, we can also cancel it midway through by using the cancel method.
my $f = repeat { my ( $prev ) = @_; SLEEP($prev ? 10 : 0)->then( sub { GET("http://my-site-here.com/try-a-thing"); }); } until => sub { $_[0]->get->code == 200 }; $SIG{INT} = sub { $f->cancel }; $f->get;
Here we have started an HTTP GET operation in a repeat loop, hoping to eventually achieve a success. If in the meantime the user gets bored and hits Ctrl-C, the SIGINT handler cancels the future representing the repeat loop. This will cause it to not continue executing another attempt, and also cascades the cancel call into its currently-running attempt. This cancel call continues to cascade down towards the individual basic futures that the entire operation is composed of. The behaviour of the then chain, for example, depends on how far the operation has progressed; in this case cancelling either the SLEEP or the GET.
The basic futures provided by event systems (such as the SLEEP call) can use the on_cancel method to register a code block to call if the future is cancelled. This could perhaps stop the event that they would use to implement the timer behaviour.
sub SLEEP { my ( $delay ) = @_; my $f = Future->new; my $id = EventSystem->timed_event( $delay, sub { $f->done } ); $f->on_cancel( sub { EventSystem->stop_timed_event( $id ); }); return $f; }
This cascading of cancellation requests allows future-based code to easily support cancelling partially-complete operations without having to implement the logic to track progress and direct the request appropriately. Simply provide on_cancel handlers for the basic future operations that make the overall activity and the request will be handled appropriately.
No comments:
Post a Comment