mirror of
https://github.com/danog/amp.git
synced 2025-01-22 21:31:18 +01:00
Fix future completing then cancelling join
If both callbacks are enqueued they may be both invoked, so only throw to the suspension if the promise isn't resolved.
This commit is contained in:
parent
e0fe64c495
commit
a7f31d1b98
@ -114,7 +114,9 @@ final class Future
|
||||
|
||||
$cancellationId = $token?->subscribe(function (\Throwable $reason) use (&$callbackId, $suspension): void {
|
||||
$this->state->unsubscribe($callbackId);
|
||||
$suspension->throw($reason);
|
||||
if (!$this->state->isComplete()) { // Resume has already been scheduled if complete.
|
||||
$suspension->throw($reason);
|
||||
}
|
||||
});
|
||||
|
||||
$callbackId = $this->state->subscribe(static function (?\Throwable $error, mixed $value) use (
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Amp\Future;
|
||||
|
||||
use Amp\CancellationTokenSource;
|
||||
use Amp\CancelledException;
|
||||
use Amp\Deferred;
|
||||
use Amp\Future;
|
||||
@ -9,6 +10,7 @@ use Amp\TimeoutCancellationToken;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Revolt\EventLoop\Loop;
|
||||
use function Amp\Future\spawn;
|
||||
use function Revolt\EventLoop\defer;
|
||||
use function Revolt\EventLoop\delay;
|
||||
|
||||
class FutureTest extends TestCase
|
||||
@ -140,6 +142,21 @@ class FutureTest extends TestCase
|
||||
self::assertTrue($future->join($token));
|
||||
}
|
||||
|
||||
public function testCompleteThenCancelJoin(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$source = new CancellationTokenSource;
|
||||
$future = $deferred->getFuture();
|
||||
|
||||
defer(function () use ($future, $source): void {
|
||||
self::assertSame(1, $future->join($source->getToken()));
|
||||
});
|
||||
|
||||
$deferred->complete(1);
|
||||
$source->cancel();
|
||||
|
||||
delay(0.01); // Tick the event loop to enter defer callback.
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
|
Loading…
x
Reference in New Issue
Block a user