fix(rack): fiber-safe context detachment in EventHandler - #2130
fix(rack): fiber-safe context detachment in EventHandler#2130rsamoilov wants to merge 3 commits into
EventHandler#2130Conversation
|
|
Store fiber reference with context token to safely skip detachment when on_finish is called from a different fiber than on_start. Spans are always finished regardless of fiber.
16aa912 to
1129d8f
Compare
| span.finish | ||
| OpenTelemetry::Context.detach(token) | ||
|
|
||
| if Fiber.current.equal?(original_fiber) |
There was a problem hiding this comment.
Could you share more details about how this could happen?
What application server are you using that invokes the rack events in different fibers?
arielvalentin
left a comment
There was a problem hiding this comment.
I am concerned about passing around references to fibers and want to better understand if we are leaking context objects or detaching them out of order.
Could you share more information or a small script that demonstrates the problem?
|
I'm using Rage, which runs each request in a separate fiber. But the issue isn't specific to Rage - it affects any setup where the response body is closed in a different fiber than the one that handled the request. Here's a minimal reproduction that demonstrates the problem using just Puma + a simple middleware: https://gist.github.com/rsamoilov/c01b3923af0a35dd75b34056062abf0a
The span always finishes regardless of which fiber we're in. The only thing skipped is the |
|
👋 This pull request has been marked as stale because it has been open with no activity. You can: comment on the issue or remove the stale label to hold stale off for a while, add the |
|
👋 This pull request has been marked as stale because it has been open with no activity. You can: comment on the issue or remove the stale label to hold stale off for a while, add the |
|
Commenting to remove the stale status, but let me know if you're not comfortable with this change and the PR should be closed. |
|
Hi @rsamoilov, I'll add this to our next SIG agenda. I hope to have more for you after that meeting. |
Now, the request itself will be attached to its context in a hash, allowing the specific context associated with that hash to be detached on finish. This should resolve issues with fiber-based frameworks and Sinatra environments that mount multiple apps.
|
Hi @rsamoilov, thanks for your patience while we reviewed your proposal. The PR raises a real concern with fiber-based frameworks that I wasn't aware of. Thank you for the reproduction script. With the growth of Fibers in Ruby, I'd like to see our Rack instrumentation better support them. After you opened this, we received a bug report from a Sinatra user (#2425) about correctly passing context in a scenario where multiple apps are mounted. I opened #2476 to fix this using a last-in, first-out context stack. That solution falls short if we're running the code in a fiber context, since fibers can attach and detach out of order. To resolve both of our issues, I suggest we consider using the Rack request itself as a reference and switching context management to a hash so we can always detach the context specifically associated with the request. This does still require instrumentation for libraries to correctly pass context for this to work. I made a branch off your work with the proposal. I wanted to draft a PR to merge into this branch, but I can't seem to find your fork. Here's the comparison in the meantime: https://github.com/open-telemetry/opentelemetry-ruby-contrib/compare/main...kaylareopelle:opentelemetry-ruby-contrib:fiber-safe-context-with-multi-app-fix?expand=1 Could you take a look and let me know what you think? I'm also happy to open this as a PR in the main repo if that's easier for you to review. |
|
Hi @kaylareopelle, One fix to tackle both problems at once - love it 😄 Your approach looks great, and I can confirm the error is fixed with these changes. I've granted you access to my fork just in case. Will be happy to review your changes either here or in another PR. |
|
Hi @rsamoilov, thank you for the access! I've opened the PR to merge my branch into this one: rage-rb#1 |
…i-app-fix fix: Update Rack context management to use hash
|
Hey @kaylareopelle , While looking at your changes, I realised there was another problem my initial fix missed. I opened rage-rb#2 - could you please give it a look? |
Summary
Fixes context detachment errors in fiber-based environments.
Problem: When using
Rack::Events, theon_finishcallback can be invoked from a different fiber thanon_start(e.g., when streaming response bodies). This causesOpenTelemetry::Context.detach(token)to fail with:Solution: Store the fiber reference alongside the token and span. On
detach_context:Note on fiber pooling: Skipping
detachcould leave stale context in the original fiber. However, servers that reuse fibers across requests would be fundamentally incompatible with any Ruby feature relying on fiber-locals (e.g.,ActiveSupport::CurrentAttributes), so this isn't something we should solve at the instrumentation level.Changes
otel.rack.token_and_spantootel.context_info[token, span]to[fiber, token, span]detach_contextto check fiber identity before detachingTest plan