Activities of "clodagh.oneill@allsop.software"

Thanks for the detailed explanation. That makes sense now and it also explains why none of the approaches I tried had any effect.

We'll go ahead with the custom per-tenant worker and use our tenant-aware DbContext to manage the background jobs instead of the built-in store.

Just out of curiosity, is there any plan to support tenant-specific background job stores (for database-per-tenant scenarios) in a future ABP release?

Hi,

We're implementing a database-per-tenant architecture where each tenant has its own SQL Server database with its own  AbpBackgroundJobs  table. We need our custom background job worker to poll each tenant's job queue independently.

Setup:

• ABP v10.3.0 (EF Core, SQL Server) • Each tenant has a "Default" connection string configured via  SaasTenantConnectionStrings  • The tenant database contains an  AbpBackgroundJobs  table with waiting jobs (confirmed via SSMS)

────────────────────

Original Approach:

Our custom  AsyncPeriodicBackgroundWorkerBase  switches tenant context before polling:

using (_currentTenant.Change(tenantId)) { using var scope = serviceProvider.CreateScope(); var jobStore = scope.ServiceProvider.GetRequiredService<IBackgroundJobStore>();

var jobs = await jobStore.GetWaitingJobsAsync(null, 100);
// Returns 0 — despite waiting jobs existing in the tenant DB

}

We expected  ICurrentTenant.Change(tenantId)  to cause the  EfCoreBackgroundJobStore  to resolve the tenant's connection string (as it does for all our other DbContext queries), but it always queries the host database.

────────────────────

Diagnostic proof that the scope IS switching correctly:

using (_currentTenant.Change(tenantId)) { using var scope = serviceProvider.CreateScope(); var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); using var uow = uowManager.Begin(requiresNew: true, isTransactional: false);

// ✅ Connection string resolver returns tenant DB
var resolver = scope.ServiceProvider.GetRequiredService&lt;IConnectionStringResolver&gt;();
var connStr = await resolver.ResolveAsync(); // → "...Initial Catalog=db-tenant..."

// ✅ Our AppDbContext connects to tenant DB
var dbContext = scope.ServiceProvider.GetRequiredService&lt;AppDbContext&gt;();
var actualDb = dbContext.Database.GetDbConnection().Database; // → "db-tenant"

// ✅ Direct EF query finds the job
var directJobs = await dbContext.BackgroundJobs
    .Where(j => !j.IsAbandoned && j.NextTryTime &lt;= now)
    .ToListAsync(); // → Count: 1

// ❌ IBackgroundJobStore still returns 0
var jobStore = scope.ServiceProvider.GetRequiredService&lt;IBackgroundJobStore&gt;();
var storeJobs = await jobStore.GetWaitingJobsAsync(null, 100); // → Count: 0

}

This proves the tenant context switch works for our  AppDbContext  but  IBackgroundJobStore  ignores it entirely.

────────────────────

What we've tried (all unsuccessful):

  1. ReplaceDbContext — Added  [ReplaceDbContext(typeof(IBackgroundJobsDbContext))]  on our  AppDbContext  and registered  options.ReplaceDbContext<IBackgroundJobsDbContext>()  in the module. ❌
  2. AbpDbConnectionOptions remapping — Configured the "AbpBackgroundJobs" database to map to "Default" with  IsUsedByTenants = true : Configure<AbpDbConnectionOptions>(options => { options.Databases.Configure("AbpBackgroundJobs", database => { database.MappedConnections.Add("Default"); database.IsUsedByTenants = true; }); });
3. IDataFilter suppression — Wrapped the call in  using (_dataFilter.Disable<IMultiTenant>())  to bypass tenant filtering on the query. ❌ (This returned jobs from the host DB instead)
4. New UnitOfWork — Created a fresh scope +  IUnitOfWorkManager.Begin(requiresNew: true)  to force EF Core to re-evaluate the connection string. ❌
5. Named connection string on tenant — Added "AbpBackgroundJobs" as a named connection string on the tenant record (in addition to "Default"). ❌

────────────────────

Question:

Is there a supported way to make  IBackgroundJobStore  (specifically  EfCoreBackgroundJobStore ) resolve to the tenant's database when  ICurrentTenant  is switched programmatically in a background worker context?

Or is the expected approach for DB-per-tenant job processing to bypass  IBackgroundJobStore  entirely and query the  BackgroundJobRecord  DbSet directly via our own DbContext (which does resolve correctly)?

Thank you.

Hi,

We're implementing a database-per-tenant architecture where each tenant has its own SQL Server database with its own  AbpBackgroundJobs  table. We need our custom background job worker to poll each tenant's job queue independently.

Setup:

• ABP Commercial 5.x (EF Core, SQL Server) • Each tenant has a "Default" connection string configured via  SaasTenantConnectionStrings  • The tenant database contains an  AbpBackgroundJobs  table with waiting jobs (confirmed via SSMS)

────────────────────

Original Approach:

Our custom  AsyncPeriodicBackgroundWorkerBase  switches tenant context before polling:

using (_currentTenant.Change(tenantId)) { using var scope = serviceProvider.CreateScope(); var jobStore = scope.ServiceProvider.GetRequiredService<IBackgroundJobStore>();

var jobs = await jobStore.GetWaitingJobsAsync(null, 100);
// Returns 0 — despite waiting jobs existing in the tenant DB

}

We expected  ICurrentTenant.Change(tenantId)  to cause the  EfCoreBackgroundJobStore  to resolve the tenant's connection string (as it does for all our other DbContext queries), but it always queries the host database.

────────────────────

Diagnostic proof that the scope IS switching correctly:

using (_currentTenant.Change(tenantId)) { using var scope = serviceProvider.CreateScope(); var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); using var uow = uowManager.Begin(requiresNew: true, isTransactional: false);

// ✅ Connection string resolver returns tenant DB
var resolver = scope.ServiceProvider.GetRequiredService&lt;IConnectionStringResolver&gt;();
var connStr = await resolver.ResolveAsync(); // → "...Initial Catalog=db-tenant..."

// ✅ Our AppDbContext connects to tenant DB
var dbContext = scope.ServiceProvider.GetRequiredService&lt;AppDbContext&gt;();
var actualDb = dbContext.Database.GetDbConnection().Database; // → "db-tenant"

// ✅ Direct EF query finds the job
var directJobs = await dbContext.BackgroundJobs
    .Where(j => !j.IsAbandoned && j.NextTryTime &lt;= now)
    .ToListAsync(); // → Count: 1

// ❌ IBackgroundJobStore still returns 0
var jobStore = scope.ServiceProvider.GetRequiredService&lt;IBackgroundJobStore&gt;();
var storeJobs = await jobStore.GetWaitingJobsAsync(null, 100); // → Count: 0

}

This proves the tenant context switch works for our  AppDbContext  but  IBackgroundJobStore  ignores it entirely.

────────────────────

What we've tried (all unsuccessful):

  1. ReplaceDbContext — Added  [ReplaceDbContext(typeof(IBackgroundJobsDbContext))]  on our  AppDbContext  and registered  options.ReplaceDbContext<IBackgroundJobsDbContext>()  in the module. ❌
  2. AbpDbConnectionOptions remapping — Configured the "AbpBackgroundJobs" database to map to "Default" with  IsUsedByTenants = true : Configure<AbpDbConnectionOptions>(options => { options.Databases.Configure("AbpBackgroundJobs", database => { database.MappedConnections.Add("Default"); database.IsUsedByTenants = true; }); });
3. IDataFilter suppression — Wrapped the call in  using (_dataFilter.Disable<IMultiTenant>())  to bypass tenant filtering on the query. ❌ (This returned jobs from the host DB instead)
4. New UnitOfWork — Created a fresh scope +  IUnitOfWorkManager.Begin(requiresNew: true)  to force EF Core to re-evaluate the connection string. ❌
5. Named connection string on tenant — Added "AbpBackgroundJobs" as a named connection string on the tenant record (in addition to "Default"). ❌

────────────────────

Question:

Is there a supported way to make  IBackgroundJobStore  (specifically  EfCoreBackgroundJobStore ) resolve to the tenant's database when  ICurrentTenant  is switched programmatically in a background worker context?

Or is the expected approach for DB-per-tenant job processing to bypass  IBackgroundJobStore  entirely and query the  BackgroundJobRecord  DbSet directly via our own DbContext (which does resolve correctly)?

Thank you.

It seems that Language Texts will need to be specified for each Tenant. We would like to change the terminology of "OrganizationUnit" to "Company" for all Tenants within the system without having to configure this individually.

Is it possible to set Language Texts at the host level, which will then be applied to all Tenants created by the host?

Showing 1 to 4 of 4 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 28, 2026, 11:44
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.