How can I cancel in-flight requests from Mojo::UserAgent?

Viewed 123

Let's say I want to cancel an in-flight request of Mojo::UserAgent? How can I do that?

2 Answers

Demonstration of how to cancel promises

In this example, we create a random Timer promise, and an HTTP Get promise. The first one that wins rejects the other promise.

use Mojo::UserAgent;
use v5.30;
use experimental 'signatures';

my $ua = Mojo::UserAgent->new;
my $p1 = Mojo::Promise->timer(rand('0.4') , 'Timeout');
my $p2 = $ua->get_p('https://www.cpanel.net/is_hiring_message_evan_carroll_on_linkedin');

$p1
  ->then(sub ($res) {$p2->reject("\t> reject \$p2"); say $res})
  ->catch(sub ($msg) {say $msg});
$p2
  ->then(sub ($res) {$p1->reject("\t> reject \$p1"); say $res})
  ->catch(sub ($msg) {say $msg});

Mojo::Promise->new->all( $p1, $p2 )->catch(sub{})->wait;

Note if the timeout wins, you may get an error event for Premature connection close that's what you'd expect. You can see here' we're utilizing Mojo::Promise's all,

Returns a new Mojo::Promise object that either fulfills when all of the passed Mojo::Promise objects have fulfilled or rejects as soon as one of them rejects. If the returned promise fulfills, it is fulfilled with the values from the fulfilled promises in the same order as the passed promises.

Note, in this case race is probably more applicable. We wouldn't have to manually reject the other promise, but I wanted to demonstrate rejection in the abstract with reject manually.

This doesn’t actually work.

Consider the following:

use Mojo::UserAgent;
use v5.26;
use experimental 'signatures';

my $ua = Mojo::UserAgent->new;
my $p1 = Mojo::Promise->timer(0.004, 'Timeout');
my $p2 = $ua->get_p('http://www.cpanel.net/is_hiring_message_evan_carroll_on_linkedin');

$p1
  ->then(sub ($res) {$p2->reject("\t> reject \$p2"); say $res})
  ->catch(sub ($msg) {say $msg});
$p2
  ->then(sub ($res) {$p1->reject("\t> reject \$p1"); say $res})
  ->catch(sub ($msg) {say $msg});

Mojo::Promise->new->all( $p1, $p2 )->catch(sub{})->wait;

Mojo::Promise->timer(2)->wait();

The changes here are to forgo SSL, to always time out after 0.004 seconds, and to have the event loop wait for an extra 2 seconds.

If you strace the above you’ll see that the request continues.

Related