diff --git a/lib/TimeoutCancellationToken.php b/lib/TimeoutCancellationToken.php index f2617e7..4c46ceb 100644 --- a/lib/TimeoutCancellationToken.php +++ b/lib/TimeoutCancellationToken.php @@ -2,6 +2,8 @@ namespace Amp; +use function Amp\Internal\formatStacktrace; + /** * A TimeoutCancellationToken automatically requests cancellation after the timeout has elapsed. */ @@ -10,11 +12,11 @@ final class TimeoutCancellationToken implements CancellationToken /** @var string */ private $watcher; - /** @var \Amp\CancellationToken */ + /** @var CancellationToken */ private $token; /** - * @param int $timeout Milliseconds until cancellation is requested. + * @param int $timeout Milliseconds until cancellation is requested. * @param string $message Message for TimeoutException. Default is "Operation timed out". */ public function __construct(int $timeout, string $message = "Operation timed out") @@ -22,9 +24,12 @@ final class TimeoutCancellationToken implements CancellationToken $source = new CancellationTokenSource; $this->token = $source->getToken(); - $this->watcher = Loop::delay($timeout, static function () use ($source, $message) { - $source->cancel(new TimeoutException($message)); + $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); + $this->watcher = Loop::delay($timeout, static function () use ($source, $message, $trace) { + $trace = formatStacktrace($trace); + $source->cancel(new TimeoutException("$message\r\nTimeoutCancellationToken was created here:\r\n$trace")); }); + Loop::unreference($this->watcher); } diff --git a/test/TimeoutCancellationTokenTest.php b/test/TimeoutCancellationTokenTest.php index 8f22641..2f31982 100644 --- a/test/TimeoutCancellationTokenTest.php +++ b/test/TimeoutCancellationTokenTest.php @@ -3,26 +3,31 @@ namespace Amp\Test; use Amp\CancelledException; -use Amp\Delayed; use Amp\Loop; use Amp\TimeoutCancellationToken; use Amp\TimeoutException; +use function Amp\delay; class TimeoutCancellationTokenTest extends BaseTest { public function testTimeout() { Loop::run(function () { + $line = __LINE__ + 1; $token = new TimeoutCancellationToken(10); $this->assertFalse($token->isRequested()); - yield new Delayed(20); + yield delay(20); $this->assertTrue($token->isRequested()); try { $token->throwIfRequested(); } catch (CancelledException $exception) { $this->assertInstanceOf(TimeoutException::class, $exception->getPrevious()); + + $message = $exception->getPrevious()->getMessage(); + $this->assertContains('TimeoutCancellationToken was created here', $message); + $this->assertContains('TimeoutCancellationTokenTest.php:' . $line, $message); } }); }