Proper async traces

This commit is contained in:
Daniil Gentili 2020-01-31 18:03:23 +01:00
parent db40848866
commit 379cd0f247
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
3 changed files with 69 additions and 104 deletions

View File

@ -58,20 +58,15 @@ final class Coroutine implements Promise, \ArrayAccess
/** @var mixed Promise success value when executing next coroutine step, null at all other times. */
private $value;
/**
* Generator trace.
*
* @var Trace
*/
private $trace;
/** @var ?self Reference to coroutine that started this coroutine */
private $parentCoroutine;
/**
* @param \Generator $generator
*/
public function __construct(\Generator $generator, Trace $trace = null)
public function __construct(\Generator $generator)
{
$this->generator = $generator;
//$this->trace = $trace ?? new Trace(\debug_backtrace());
try {
$yielded = $this->generator->current();
@ -92,24 +87,13 @@ final class Coroutine implements Promise, \ArrayAccess
return;
}
if ($yielded instanceof \Generator) {
/*if ($this->generator->valid()) {
$reflection = new ReflectionGenerator($this->generator);
$trace = new Trace(
[[
'file' => $reflection->getExecutingFile(),
'line' => $reflection->getExecutingLine(),
'function' => $reflection->getFunction()->getName(),
]],
$this->trace
);
} else {
$trace = $this->trace;
}
$yielded = new self($yielded, $trace);*/
$yielded = new self($yielded);
} else {
$yielded = $this->generator->send($yielded);
}
if ($yielded instanceof self) {
$yielded->parentCoroutine = $this;
}
}
} catch (\Throwable $exception) {
$this->fail($exception);
@ -133,7 +117,7 @@ final class Coroutine implements Promise, \ArrayAccess
do {
if ($this->exception) {
// Throw exception at current execution point.
$yielded = $this->generator->throw($this->exception);
$yielded = $this->throw($this->exception);
} else {
// Send the new value and execute to next yield statement.
$yielded = $this->generator->send($this->value);
@ -163,6 +147,9 @@ final class Coroutine implements Promise, \ArrayAccess
$yielded = $this->generator->send($yielded);
}
}
if ($yielded instanceof self) {
$yielded->parentCoroutine = $this;
}
$this->immediate = false;
$yielded->onResolve($this->onResolve);
} while ($this->immediate);
@ -178,14 +165,32 @@ final class Coroutine implements Promise, \ArrayAccess
$yielded->onResolve($this->onResolve);
}
/**
* Throw exception into the generator
*
* @param \Throwable $reason Exception
*
* @internal
*
* @return void
*/
public function throw(\Throwable $reason)
{
if (!isset($reason->yieldedFrames)) {
if (method_exists($reason, 'updateTLTrace')) {
$reason->updateTLTrace($this->getTrace());
} else {
$reason->yieldedFrames = $this->getTrace();
}
}
$this->generator->throw($reason);
}
/**
* @param \Throwable $reason Failure reason.
*/
public function fail(\Throwable $reason)
{
//if (isset(\class_uses($reason)[TL\PrettyException::class])) {
//$reason->updateTLTrace($this->getTrace());
//}
$this->resolve(new Failure($reason));
}
@ -246,13 +251,48 @@ final class Coroutine implements Promise, \ArrayAccess
return $result->{$name}($arguments);
})());
}
/**
* Get stacktrace from when the generator was started.
* Get current stack trace for running coroutine.
*
* @return array
*/
public function getTrace(): array
{
return $this->trace->getTrace();
$frames = [];
try {
$reflector = new ReflectionGenerator($this->generator);
$frames = $reflector->getTrace();
$frames []= \array_merge(
$this->parentCoroutine ? $this->parentCoroutine->getFrame() : [],
[
'function' => $reflector->getFunction()->getName(),
'args' => []
]
);
} catch (\Throwable $e) {
}
if ($this->parentCoroutine) {
$frames = \array_merge($frames, $this->parentCoroutine->getTrace());
}
return $frames;
}
/**
* Get current execution frame
*
* @return array
*/
public function getFrame(): array
{
try {
$reflector = new ReflectionGenerator($this->generator);
return [
'file' => $reflector->getExecutingFile(),
'line' => $reflector->getExecutingLine(),
];
} catch (\Throwable $e) {
}
return [];
}
}

View File

@ -392,7 +392,7 @@ trait ResponseHandler
return;
}
if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running', 'No workers running'])) {
if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'HISTORY_GET_FAILED', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running', 'No workers running'])) {
Loop::delay(1 * 1000, [$this, 'methodRecall'], ['message_id' => $request_id, ]);
return;
}

View File

@ -1,75 +0,0 @@
<?php
/**
* ResponseHandler module.
*
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
namespace danog\MadelineProto;
/**
* Represents a piece of a coroutine stack trace.
*/
class Trace
{
/**
* Next piece of the stack trace.
*
* @var Trace
*/
private $next;
/**
* Current stack trace frames.
*
* @var array
*/
private $frames = [];
/**
* Create trace.
*
* @param array $frames Current frames
* @param self $next Next trace
*/
public function __construct(array $frames, self $next = null)
{
$this->frames = $frames;
$this->next = $next;
}
/**
* Get stack trace.
*
* @return array
*/
public function getTrace(): array
{
return \iterator_to_array($this->getTraceGenerator());
}
/**
* Get stack trace.
*
* @return \Generator
*/
private function getTraceGenerator(): \Generator
{
foreach ($this->frames as $frame) {
yield $frame;
}
if ($this->next) {
yield from $this->next->getTraceGenerator();
}
}
}