2013/12/15

Futures advent day 15

Day 15 - Performing an Action Repeatedly

So far in this series we have been performing future-based actions that might succeed, or might fail, and combined them up into larger operations of success or failure. One fairly standard way of handling failures in application logic is by attempting to retry. We couldn't simply put a future get call inside a perl while {} loop, because then the loop itself would block until success and we couldn't do anything else at the same time.

Instead, we can use a function from the Future::Utils package called repeat. This takes a block of code which returns a future, and returns a future representing the operation of repeatedly calling that code and waiting for its future to finish, until some ending condition is satisfied. This condition is specified by a second block of code given as either the until or while arguments.

use Future::Utils qw( repeat );

my $f = repeat {
  POST("http://my-site-here.com/new", $form)
} until => sub { $_[0]->get->code == 200 };

my $page = $f->get;

Each time around the loop we will attempt to POST to the resource. When this HTTP operation finishes the until condition is tested. In this example, we are looking for a 200 OK response from HTTP. If we get any other response, we'll try again. The entire operation is represented by the future returned in $f. When we eventually get a response that is deemed acceptable, the overall future $f will receive its result.

In this rather simple example we'll retry each attempt immediately, with no limit on the number of retries. A more practical example would apply a delay between each call, and limit the number of retries. Let us now suppose we have a sleep-like function, DELAY, which returns a future that will complete some number of seconds later.

my $retries = 5;

my $f = repeat {
  my ( $prev ) = @_;

  DELAY($prev ? 10 : 0)
    ->then( sub {
      POST("http://my-site-here.com/new", $form)
    })
} while => sub { $_[0]->get->code != 200 and
                 $retries-- };

my $page = $f->get;

Here we keep a count of the number of retry attempts, and stop retrying once we run out of them. We can implement the pause between retries by asking the DELAY function for a pause of either 0 or 10 seconds, depending on whether there had been a previous failure (this being indicated by the presence or absence of the previous future being passed in to the code body).

<< First | < Prev | Next >

No comments:

Post a Comment