Finbuckle / Finbuckle.MultiTenant

Finbuckle.MultiTenant is an open-source multitenancy middleware library for .NET. It enables tenant resolution, per-tenant app behavior, and per-tenant data isolation.
https://www.finbuckle.com/multitenant
Apache License 2.0
1.32k stars 267 forks source link

Using Multitenant inside a Hangfire batch #485

Open auri179 opened 2 years ago

auri179 commented 2 years ago

Hello,

We have an issue using multitenant inside Hangfire batch. We are using multitenant in header strategy and when we are in controllers everything is fine. But for some reasons we have to bulk edit some entities asynchronously, for that we are using Hangfire jobs. The entity to update is a multitenant entity and inside hangfire job the HttpContext is not valued because we are not in a HttpRequest... All the time the DbContext is raising an exception "MultiTenant Entity cannot be changed if TenantInfo is null.". We are only in update mode and we d'ont have to update the tenant because we are tenant scoped.

What can we do to achieve this ?

Thanks

AndrewTriesToCode commented 2 years ago

Hi I'm not familiar with Hangfire jobs, but I think I can see what is happening. The DbContext(s) are being spun up with a null TenantInfo object. In normal cases it tries to protect from changes like this but I understand your situation it would make sense to allow bulk updates for efficiency. I was about to point you toward TenantNotSetMode but I see we don't have an option there that would help you. I think I add an Ignore option there to the ToDo list, but for now unfortunately it won't work.

Is it possible that you can break up your bulk edit into bulk edit by tenant and for each one spin up a dbcontext with a TenantInfo object containing the correct TenantId?

SkualoSpA commented 2 years ago

I've kind of the same problem.

As I could research about this, TenantInfo is stored over HttpContext but HangFire doesn't use HttpContext... :(.

Any alternative to store TenantInfo in some other place?

For now I solved this doing HangFire make a HTTP request back to my API, but I think this is not optimal ... API -> HangFire -> API

AndrewTriesToCode commented 2 years ago

Hi, TenantInfo isn't really stored in HttpContext, but rather in a global IMultiTenantAccessor<T> instance which uses an AsyncLocal<MultiTenantContext<T>> to store the current multitenant context. Do you have access to DI where the code is needed? You might be able to inject IMultiTenantContextAccessor<T> and use it to get to the tenant info.

tiesont commented 2 years ago

I'm assuming this happens because the background job is using something that has a dependency on a EFCoreStoreDbContext data context?

If so, can the job be rewritten to remove that dependency, since it sounds like what you're doing isn't really tenant-specific?

For my Hangfire jobs, I try to make them as atomic as possible - this allows me to enqueue them in a few different contexts (within ASP.NET Core and within TopShelf-enabled background services, for example) without adding a lot of transitive dependencies.

(Sorry, wasn't paying attention to the issue date - this was probably resolved a while ago)