Skip Menu |

This queue is for tickets about the future CPAN distribution.

Report information
The Basics
Id: 91147
Status: resolved
Priority: 0/
Queue: future

People
Owner: Nobody in particular
Requestors: TEAM [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.20
Fixed in: 0.21



Subject: Attempting to mark as ->done when cancelling repeat { }
Seems that calling ->cancel on a repeat {} block can cause things to be marked as done. Does the attached test case look valid? This is from a larger piece of code which uses timeouts to cancel various actions, the 'already cancelled and cannot be ->done' error seems to crop up every now and then and I *think* this is the cause. # Repeat cycle ok 1 - mark trial as done # Cancel repeat future # Repeat cycle ok 2 - can cancel repeat future # Repeat cycle Future=HASH(0xf1ae08) is already cancelled and cannot be ->done at .../Future.pm line 565. Future::done(Future=HASH(0xf1ae08)) called at .../Future.pm line 837 Future::on_done(Future=HASH(0xf2ecf8), Future=HASH(0xf1ae08)) called at .../Future/Utils.pm line 204 Future::Utils::_repeat(CODE(0xa24770), Future=HASH(0xf1ae08), REF(0xc3b8f0), CODE(0xf1ab20), 0) called at .../Future/Utils.pm line 196 Future::Utils::__ANON__(Future=HASH(0xf2ecf8)) called at .../Future.pm line 516 Future::_mark_ready(Future=HASH(0xf2ecf8)) called at .../Future.pm line 568 Future::done(Future=HASH(0xf2ecf8)) called at util-cancel.t line 14 cheers, Tom
Subject: util-cancel.t
use strict; use warnings; use Test::More; use Future; use Future::Utils qw(repeat); use IO::Async::Loop; my $loop = IO::Async::Loop->new; my $count = 3; my $test = repeat { my $f = Future->new; $loop->later(sub { ok($f->done, 'mark trial as done') unless $f->is_ready }); $f } while => sub { note "Repeat cycle"; --$count }; $loop->later(sub { note "Cancel repeat future"; ok($test->cancel, 'can cancel repeat future'); }); $test->on_ready(sub { $loop->later(sub { $loop->stop }) }); $loop->run; pass("Finished loop"); done_testing;
Note that checking ->is_ready in the while => sub { ... } block prevents the error. Maybe this behaviour is by design? If so, it'd be useful to document this. cheers, Tom
err... that should of course be ->is_cancelled, not ->is_ready. On Tue Dec 03 13:41:15 2013, TEAM wrote: Show quoted text
> Note that checking ->is_ready in the while => sub { ... } block > prevents the error. Maybe this behaviour is by design? If so, it'd be > useful to document this. > > cheers, > > Tom
On Tue Dec 03 07:43:27 2013, TEAM wrote: Show quoted text
> Seems that calling ->cancel on a repeat {} block can cause things to > be marked as done. Does the attached test case look valid?
Just to confirm it's not IO::Async-related, the attached rewrite also fails. -- Paul Evans
Subject: 90rt91147.t
#!/usr/bin/perl use strict; use warnings; use Test::More; use Future; use Future::Utils qw(repeat); my $count = 3; { my @later; sub later { push @later, $_[0] } sub run { ( shift @later )->() while @later } } my $test = repeat { my $f = Future->new; later( sub { ok( $f->done, 'mark trial as done' ) unless $f->is_ready }); $f } while => sub { note "Repeat cycle"; --$count }; later( sub { note "Cancel repeat future"; ok( $test->cancel, 'can cancel repeat future' ); }); run(); pass("Finished loop"); done_testing;
Got it. That pesky ->on_ready being invoked even after cancel. Find patch attached. In this situation I'm starting to consider not having ->on_ready invoked after cancellation. For those rare times you might want that, have a ->on_ready_or_cancel. -- Paul Evans
Subject: 90rt91147.t
#!/usr/bin/perl use strict; use warnings; use Test::More; use Future; use Future::Utils qw(repeat); my $count = 3; { my @later; sub later { push @later, $_[0] } sub run { ( shift @later )->() while @later } } my $test = repeat { my $f = Future->new; later( sub { ok( $f->done, 'mark trial as done' ) unless $f->is_ready }); $f } while => sub { note "Repeat cycle"; --$count }; later( sub { note "Cancel repeat future"; ok( $test->cancel, 'can cancel repeat future' ); }); run(); pass("Finished loop"); done_testing;
On Wed Dec 04 10:08:46 2013, PEVANS wrote: Show quoted text
> Find patch attached.
Uh, or maybe this time I'll attach the patch and not the unit-test file... -- Paul Evans
Subject: rt91147.patch
=== modified file 'lib/Future/Utils.pm' --- lib/Future/Utils.pm 2013-11-18 19:15:41 +0000 +++ lib/Future/Utils.pm 2013-12-04 15:05:39 +0000 @@ -193,6 +193,7 @@ # defer $return ||= $trial->new; $trial->on_ready( sub { + return if $$trialp->is_cancelled; _repeat( $code, $return, $trialp, $cond, $sense ); }); return $return; === modified file 't/30utils-repeat.t' --- t/30utils-repeat.t 2013-09-20 18:05:47 +0000 +++ t/30utils-repeat.t 2013-12-04 15:05:39 +0000 @@ -65,8 +65,9 @@ $future->cancel; - ok( $running[1]->is_cancelled, 'running future cancelled after eventual is cancelled' ); ok( !$running[0]->is_cancelled, 'previously running future not cancelled' ); + ok( $running[1]->is_cancelled, 'running future cancelled after eventual is cancelled' ); + ok( !$running[2], 'a third trial is not started' ); } # until
Now released in 0.21. -- Paul Evans