Skip to content
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

ModelBuilder being thread safe? #15243

Closed
hkoestin opened this issue Apr 3, 2019 · 3 comments
Closed

ModelBuilder being thread safe? #15243

hkoestin opened this issue Apr 3, 2019 · 3 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@hkoestin
Copy link

hkoestin commented Apr 3, 2019

Hello,

This here is not really an issue but more of a question, but since I have not found anything helping on the internet and the mighty search engine of your choice, I wanted to ask that in here.

I know, that per design, EF Core was not meant to be thread safe. I totally get that point of isolation for the DbContext instances, but I was wondering, why also the model building already seems to be impacted by that.

Background

In order to speed up start-up time for an application, I wanted to do 2 queries in parallel, using 2 distinct DbContexts. Basically, each of them reflects a "Bounded Context Database" in my domain, one mapping to environment settings (user settings, stored UI layouts, ...) in the database and one mapping to system settings (system passwords, ...).

So when I fire up the application, I wanted to start two tasks, one going to the environment settings to fetch already the layout stuff and user settings, and one going to the system settings, to check on correct passwords etc.

Problem

Both tasks would create the underlying DbContext on their own, so the DbContext is created at that thread. But somehow, it seems, that the actual model-building under the hood of EF Core is done differently or not "per" thread or "per DbContext".

When I execute my application, from time to time it crashes with the following error:

System.InvalidOperationException: Cannot create a DbSet for 'EvaluationSettings' because this type is not included in the model for the context.

Having a look at my logs however reveals, that the entity was registered at the context previously.

  • Thread 18 is for the system stuff and registeres SystemInformation and Variable at its context and calls "EnsureCreated"
  • Thread 16 is for getting culture settings etc and registers Evaluation, EvaluationSettings, ... at the context and calls "EnsureCreated"

Afterwards, thread 16 (getting the system culture from the EvaluationSettings entity) fails.

image

When I do debug that issue and try to get the insights of the model-builder, I see, that only the Evaluation type is known to the DbContext model builder. The rest somehow is gone.

image

Question

Could it be, that because 3 threads are calling "EnsureCreated" in parallel, only those entities get a model in the context, which were registered at that point of time?
It seems, that on that level, there is no isolation of "this model belongs to that context", right?

Anybody has a possible solution to that?
Or a suggestion how to solve that?

Version

EF Core 2.2.1

@hkoestin hkoestin changed the title ModelBuilder / DbSet being thread safe ModelBuilder being thread safe? Apr 3, 2019
@hkoestin
Copy link
Author

hkoestin commented Apr 3, 2019

I did ask the question also on SO: https://stackoverflow.com/q/55488880/8504288

@ajcvickers
Copy link
Member

@hkoestin Since EnsureCreated is manipulating the database schema, it must not be called concurrently from multiple threads. Even if we did allow two threads to call into it concurrently, this would only work if one of the threads blocks, which is what you are already seeing for model creation. Continuing with the model, it is built once and cached because generally building the model can be slow. By default, models are cached based on the DbContext type, but this can be configured. So you could build two models in parallel if you wanted to. In general this is unlikely to be good for perf.

@hkoestin
Copy link
Author

hkoestin commented Apr 4, 2019

@ajcvickers thank you for your feedback. I see, that there is no point in seeking for a performance boost in this topic. Will just call the ensure created once. I see, that model building is quite costly and that is the reason why EF tries to cache it etc.

However, the models which needs to be built are very specific to the DbContext, namely only the registered entities in that very DbContext. Why isn't there a mechanism in place, which sort of isolates the models per db-context type? Then, model building (also for huge mappings with tons of entities etc.) can happen on a very small and limited subset (each DbContext). The database facade would need to have a cache in place, which of the models for which DbContext were already build etc.

I tried something different now: one DbContext pointing to SQLite, one pointing to SQL Server. There, building works in parallel. At least, out of maybe 20 runs, I did not see an issue.

@ajcvickers ajcvickers added closed-no-further-action The issue is closed and no further action is planned. customer-reported labels Apr 5, 2019
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported
Projects
None yet
Development

No branches or pull requests

2 participants