First thanks for this awesome project.
And let's come to my weird issue.
Describe the Issue
When I try to query single entities from my ef core context using the CacheDataloader the query fails randomly a couple of times and then magically works.
This issue only appears when I try to query different entities at a time.
To Reproduce
Steps to reproduce the behavior:
Code
I have this inside my RootQuery Schema
``` c#
// User
descriptor.Field("user")
.Argument("id", a => a.Type
.Type
.Resolver( async ctx =>
{
var userId = ctx.Argument
var data = await ctx.CacheDataLoader
id => ctx.Service
.FirstOrDefaultAsync(u => u.Id == userId)).LoadAsync(userId);
return data;
});
descriptor.Field("app")
.Argument("id", a => a.Type
.Type
.Resolver( async ctx =>
{
var appId = ctx.Argument
var data = await ctx.CacheDataLoader
id => ctx.Service
.FirstOrDefaultAsync(a => a.Id == appId)).LoadAsync(appId);
return data;
});
```
Here is a gif of this:
https://imgur.com/pLumz9N
Not sure what is causing this.
Regards Artur
Hi Arthur,
I will try to setup a repro of this over the weekend.
@S0PEX could you enable the exception details and repeat your test. I do not get this error with my tests.
services.AddGraphQL(Schema.Create(c =>
{
// ...
}),
new QueryExecutionOptions { IncludeExceptionDetails = true });
Here you go:
{
"errors": [
{
"message": "Unexpected Execution Error",
"locations": [
{
"line": 6,
"column": 4
}
],
"path": [
"user"
],
"extensions": {
"message": "An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point. This can happen if a second operation is started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.",
"stackTrace": " at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()\n at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()\n at Microsoft.EntityFrameworkCore.DbContext.get_Model()\n at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()\n at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()\n at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsNoTracking[TEntity](IQueryable`1 source)\n at GraphQL.Queries.RootQuery.<>c__DisplayClass0_0.<Configure>b__6(Int32 id) in /Users/s0pex/Git/Uni/Website/SCS/GraphQl.Server/Queries/RootQuery.cs:line 26\n at HotChocolate.DataLoader.FetchSingleDataLoader`2.FetchAsync(IReadOnlyList`1 keys, CancellationToken cancellationToken)\n at GraphQL.Queries.RootQuery.<>c.<<Configure>b__0_1>d.MoveNext() in /Users/s0pex/Git/Uni/Website/SCS/GraphQl.Server/Queries/RootQuery.cs:line 25\n--- End of stack trace from previous location where exception was thrown ---\n at HotChocolate.Configuration.ResolverRegistry.<>c__DisplayClass21_0.<<CreateResolverMiddleware>b__0>d.MoveNext()\n--- End of stack trace from previous location where exception was thrown ---\n at HotChocolate.Execution.ExecutionStrategyBase.ExecuteFieldMiddlewareAsync(ResolverTask resolverTask)\n at HotChocolate.Execution.ExecutionStrategyBase.ExecuteMiddlewareAsync(ResolverTask resolverTask, IErrorHandler errorHandler)"
}
}
],
"data": {
"App": {
"id": "1",
"name": "Awesome Dummy App"
},
"user": null
}
}
Weird multithreading issue I guess. Maybe I should make the Context transient instead of the default AddDatabaseContext which is scoped ?
Sorry @S0PEX,
I was out with a migraine the last two days.
If you are registering you context as transient then you need to take care of disposing it.
Why are you not using the batch data loader in your case since you could easily do that with your context. But this would not fully fix the thread issues, since other DataLoader could access you context.
Transient could be the best option here.
You should also join our slack channel and ask the question there again .... some users might have had the same issue and It might be worth asking for their solutions.
I am closing this issue since the initial problem is solved.
Currently solved this issue by using the pooled version (AddDbContextPool).
I have found out an alternative solution for this problem, using a custom asp middleware, custom data context factory, and transient datacontexts.
Please have a look at it: demo repo
How could this solution improved further?
Are you going to provide an "official" solution for this problem in v11?
This is now solved with the upcoming resource concept in 10.4
Quick note: I'm currently required to work with v11 preview which is missing the ForceSerialExecution option. Setting the service lifetime to Transient doesn't work when your query fetches from multiple DbSets. For example: query Test{SomeStuff{Id} SomeMoreStuff{Name}} will still fail, albeit intermittently depending on timing. This blog post says there's DbContext pooling on it's way but I haven't been able to find anything. Maybe it's not out yet? In the meantime I'm constructing a new DbContext for each relevant field.
descriptor.Field("Test")
.Description("Test info")
.Type<ListType<TestType>>()
.UseSelection()
.UseFiltering()
.UseSorting()
.Authorize("AdminPolicy")
.Resolver(() => new DatabaseContext().Test); //< This here
descriptor.Field("SomeMoreStuff")
.Description("Some more stuff")
.Type<ListType<SomeMoreStuffType>>()
.UseSelection()
.UseFiltering()
.UseSorting()
.Authorize("AdminPolicy")
.Resolver(() => new DatabaseContext().SomeMoreStuff); //< This here
@IKingJohnI we are currently writing a new execution engine for version 11, this is why we do not port some of the 10 features since we would essentially put work in something that will be gone in two weeks.
Once the new execution engine is in place we will port missing features. Although version 11 will have than better capabilities to do ef with DBContext pooling.
Excellent, I'm looking forward to it! Hot Chocolate and Strawberry Shake rock!
@michaelstaib is new execution engine and dbContext pooling already implemented in new 11.0.0-dev.11 ?
@garfieldos yes, but I would use dev.13 which brings in more bug fixes.
@michaelstaib Is there something to change to be able to pool dbContext ?
I have an issue with the v10, when I use "ForceSerialExecution" and DataLoaders, it does not batch the queries, so I removed "ForceSerialExecution" but in that case, I can make query selecting two different fields from the root one as I get the issue of parallel execution.
I tried with the v11 and it didn't change anything so I'm wondering if something has to be changed?
Thanks
ForceSerialExecution is gone. We already do not recommend it anymore with 10.5.
Have you looked at our workshop:
https://github.com/ChilliCream/graphql-workshop
I indeed had to remove ForceSerialExecution when I tried with the v11.
As for the workshop, I quickly went through it but it seemed not up to date.
For example, it says:
services.AddGraphQL(
SchemaBuilder.New()
.AddQueryType<Query>());
While it seems that now, I have to use "AddGraphQLServer".
Now, when I checked on the session #1, it does seem that the DbContext are added in a regular way.
In my solution, I'm using "AddDbContextPool" along with a SQL Server database.
Basically, if I have something like:
{
foo {
bar
baz {
shoo
}
}
}
It works very well, but as soon as I do something like:
{
foo {
bar
baz {
shoo
}
}
other {
...
}
}
Then I have the issue :
"A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext."
Note that my DbContext is scoped and I cannot changed it as I developed the whole application with this in mind and that would probably cause a lot of issue in it if I changed them to Transient.
Cheers
If you have further questions please head over to our slack channel or open a new issue.