-
Notifications
You must be signed in to change notification settings - Fork 181
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
[ActiveRecord] Add Attributes for Async Queries #1219
Comments
Thank you for opening this! 🙇🏻 It would also be great if we could include the |
👋 This issue 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 |
I can work on this. |
Thanks, @zvkemp! I've assigned this issue to you. |
@arielvalentin I have a few clarifying questions on this. The current ActiveRecord::Instrumentation patches _query_by_sql, which happens before any decisions about asynchrony are made (the caller may request the query should be async, but can't require it). If The second wrinkle is in retrieving the result from the promise — even if it is successfully scheduled, if the task is still not enqueued by the time the original thread requests the result, the query is executed synchronously. At this point Span A is finished (so it's not permitted to change its name or other attributes), so the execution should be wrapped in a new span. If the task has started, but hasn't returned a result yet, the caller thread waits until it can acquire the tasks's mutex (indicating the thread pool is done with it), and records the So onto the question of how to enrich SpanA — in the case that it was actually async, there should probably be:
The parentage of SpanB is a somewhat tricky problem — its fairly straightforward to wrap the task using SpanA as a parent, though because of asynchrony, SpanB may be started after SpanA is finished (is this even valid? The spec doesn't seem to prohibit it), like this:
In the case where the task was scheduled but not picked up yet:
^ In this case, SpanB is still a child of SpanA, though in reality it would be more correct to make it a child of SpanC. I'm not sure how that re-parenting would work though, unless we delay deciding on a span context until the query is actually fired. |
@zvkemp these are all great points and thank you for the illustrations because they highlight the complexity around how our currently implementation does not work well with concurrent or parallel workflows. open-telemetry/opentelemetry-ruby#1766 Knowing that AR et.al. internals are using Concurrent Ruby is what prompted me to add its instrumentation as a dependency for Rails. I do not have an answer here for this except that it may mean we need to model this differently, i.e. potentially having multiple spans, and/or implement this a way that uses context propagation differently between threads and fibers, which then requires the backend to stich the graph together properly, but we would not be able to enrich parent spans like this issue would like. |
I'll further add that So here's a clearer picture of the 5 scenarios that can happen using
^ this is the only scenario where ActiveRecord would have reported a non-zero/non-nil lock_wait time - the
(to_a was called before a worker became available, so the executor was pre-empted). This may also happen if
(executor executes the task inline instead of enqueuing it).
So As to the question of how to tell whether the span was async — we can certainly annotate that it was requested to be asynchronous (meaning that under some conditions it probably would be), but short of comparing thread object_ids, it's not really possible to reliably tell based on the callsite or arguments whether the query was executed in the request thread or in the executor's thread pool. I think there are some improvements to be made here, the main one being that currently, async loads (scenarios 1 or 2) have a span that only wraps the scheduler, not the query itself, so the traces are misleading at best. |
ActiveRecord
7.1 introduced async query methods1, which leverages concurrency primitives viaPromise
API to defer executing queries.We would like to enrich
ActiveRecord
related spans to know whether or not they were executed from the async context.Additional Notes
The
sql.active_record
notification payload includes aasync
attribute:https://github.com/rails/rails/blob/616d3a7675c18ae2d38d3116de47e2e7308cfbd8/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L1135
We may be able to enrich the
ActiveRecord
span and amend it as a Shared DB attribute for the driver itself however we do not currently use notifications in this instrumentation.Worst case scenario, we monkey patch existing
async
methods, concurrency primitives.Footnotes
https://github.com/rails/rails/pull/44446 ↩
The text was updated successfully, but these errors were encountered: