-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unexpected call to Scope::detach() in asynchronous environment. #1199
Comments
I have not tried this before, but looking at the code for the |
Yes, |
Scopes must be detached in the execution context (Fiber/Coroutine) they were created in. $span = $tracer->spanBuilder('init')->startSpan();
$scope = $span->activate();
Loop::addTimer(5, async(function () use ($span) {
$span->end();
}));
$scope->detach(); Note that the context is not propagated to event loop callbacks by default ref.: open-telemetry/context. I am not aware of an implementation that handles this directly for ReactPHP, but you could try using https://github.com/Nevay/opentelemetry-revolt-adapter with https://github.com/revoltphp/event-loop-adapter-react. |
Thanks @Nevay. I will look into this further. I was under the impression this would work since otel keeps track of fibers and the I'm unsure about how the code in your example would work since the |
@Nevay Does this make more sense? $span = $this->tracer->spanBuilder('init')->startSpan();
$scope = $span->activate();
$context = Context::getCurrent();
$span->addEvent('something happened');
Loop::addTimer(5, async(function () use ($span, $context) {
$scope = $context->activate();
$span->addEvent('event added from timer');
$span->end();
$scope->detach();
}));
$scope->detach(); |
It would work if This is the correct usage / what should be done by the event loop on callback registration to preserve the context without having to pass it around. Using the example function from $span = $tracer->spanBuilder('init')->startSpan();
$scope = $span->activate();
$span->addEvent('something happened');
// Loop::addTimer(5, async(function () use ($span) {
Loop::addTimer(5, bindContext(async(function () use ($span) {
assert($span === Span::getCurrent());
$span->addEvent('event added from timer');
$span->end();
})));
$scope->detach();
function bindContext(Closure $closure): Closure {
$context = Context::getCurrent();
return static function (mixed ...$args) use ($closure, $context): mixed {
$scope = $context->activate();
try {
return $closure(...$args);
} finally {
$scope->detach();
}
};
} |
I think we need some documentation and examples for context + async/fibers in https://opentelemetry.io/docs/instrumentation/php/ |
Thanks for the example @Nevay, that clears things up. I'll create a decorator for the ReactPHP event loop and report back. |
@brettmc I'm guessing using the gRPC transport also blocks the event loop? If that's the case we'll have to document that as well. |
Somewhat related to this issue, I started writing some doco for Context in open-telemetry/opentelemetry.io#3857 |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Describe your environment
PHP 8.3, ext-ffi enabled, using Fibers with ReactPHP.
Steps to reproduce
Obviously the real life example makes more sense but the code above demonstrates the problem rather well.
What is the expected behavior?
I'm expecting the scope to be detached without notice. As per the documentation the context is being detached after the span is ended.
What is the actual behavior?
The following notice is printed:
Notice: Scope: unexpected call to Scope::detach() for scope #2654, scope successfully detached from different execution context in DebugScope.php on line 48
It looks like the
BatchSpanProcessor
is callingdetach
on thespan
before I have the chance to do it.The text was updated successfully, but these errors were encountered: