-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Using multiple DbCommandInterceptor doesn't play nice in AsyncLocal #22766
Comments
EF Team Triage: Closing this issue as the requested additional details have not been provided and we have been unable to reproduce it. BTW this is a canned response and may have info or details that do not directly apply to this particular issue. While we'd like to spend the time to uniquely address every incoming issue, we get a lot traffic on the EF projects and that is not practical. To ensure we maximize the time we have to work on fixing bugs, implementing new features, etc. we use canned responses for common triage decisions. |
Hi @ajcvickers , Thanks! |
Seems like I cannot reopen this issue. @ajcvickers Would you mind reopening it since its still an ongoing investigation? Thanks. |
@AndriySvyryd @roji This repros for me, but I don't know what is happening. I'm guessing the sync context is getting lost here, but I don't know how or why. |
@srprash |
I just had a race condition with @AndriySvyryd :)
As far as I can tell this is actually simpler: when there's just one interceptor, there's no async state machine anywhere, since there's no async/await keywords; it's simple, synchronous code. Once you have two interceptors, you get a DbCommandInterceptorAggregator which does async/await. And as @AndriySvyryd wrote above, the ExecutionContext (which AsyncLocal relies on) only flows down, not up. You can produce the same effect with a single interceptor by adding the async keyword on the the interceptor's ReaderExecutingAsync method signature. Here's a minimal code sample that shows what's going on: class Program
{
public static async Task Main()
{
AsyncLocal.Value = "First value";
await Async(); // With this, "First value" is printed
// await NonAsync(); // With this, "Second value" is printed
Console.WriteLine(AsyncLocal.Value);
}
static async Task Async()
{
AsyncLocal.Value = "Second value";
}
static Task NonAsync()
{
AsyncLocal.Value = "Second value";
return Task.CompletedTask;
}
public static AsyncLocal<string> AsyncLocal = new AsyncLocal<string>();
} |
TIL something else I didn't know about .NET async. Over the years, async has been a very fruitful source of learning experiences. |
I may have an idea of the original sentence that got euphemized into this 🤣 |
Hi @roji @AndriySvyryd Is there a way to ensure AsyncLocal storage is synced with the context in |
Hi @roji @AndriySvyryd |
@srprash You can add things to AsyncLocal beforehand and have them available in both methods. But there is no reliable way of passing data from |
Moved from discussion #22749
Question
From @srprash
Hi,
I have a sample ASPNetCore webapp which uses EFCore to add or retrieve users to a postgres db. In addition to this, I'm using AWS X-Ray .Net SDK to trace these operations by adding the
EFInterceptor
along with a custom emptyMyDbCommandInterceptor
. I'm using the empty interceptor for simplicity. The issue happens with any interceptor used with theEFInterceptor
.The AWS X-Ray SDK uses
AsyncLocal
to store the trace context of the app. When I use just use one of the interceptors, everything works fine. However, when both the interceptors are used together, the trace context gets messed up and becomes inconsistent across threads for async calls involvingExecuteReaderAsync
. The interceptors work fine together for any synchronous operation to the db.I've opened a related issue on X-Ray SDK's repo with more details pertaining to the error on the SDK but while digging into the cause of the problem, I established that the issue is with AsyncLocal not being consistent for threads invoking
ReaderExecutingAsync
andReaderExecutedAsync
methods before and after an async call to my postgres db.I wonder if using multiple
DbCommandInterceptor
s has an impact on separate threads and their thread local storage. Also,ReaderExecutingAsync
andReaderExecutedAsync
methods seem to execute on different threads. Is there a way to ensure they run on same thread or to propagate a context between these methods?I'm hoping to get some direction from this discussion to investigate the problem further and resolve it. Any help is greatly appreciated :)
Replies
From @roji
@srprash can you please submit a minimal console app which demonstrates to inconsistency with? AFAIK the interceptors shouldn't be interfering with AsyncLocal in any way.
(Note that this isn't about thread-local storage, which does not persist across asynchronous operations since those don't necessarily continue on the same thread where they began. This is why AsyncLocal is needed).
The text was updated successfully, but these errors were encountered: