ABP / module versions:
Volo.AIManagement.VectorStores.Pgvector 10.2.0 Volo.Abp.BlobStoring.Azure 10.2.0 All other Volo packages 10.2.0 ABP Framework 10.x (matching) .NET 10.0 DB: SQL Server (Azure SQL), background-jobs provider: default Volo.Abp.BackgroundJobs.EntityFrameworkCore
When a non-host (saas tenant) user uploads a Workspace Data Source PDF, the file is correctly stored in Azure Blob Storage under the multi-tenant path:
triarch-blobs/tenants/{tenantId}/{workspaceId}/{dataSourceId}.pdf …but IndexDocumentJob runs ~minutes later as host and looks up the blob without the tenants/{tenantId}/ prefix, producing:
Volo.Abp.AbpException: Could not find the requested BLOB '{workspaceId}/{dataSourceId}.pdf' in the container 'workspace-data-sources'! at Volo.Abp.BlobStoring.BlobContainer.GetAsync(...) at Volo.AIManagement.BackgroundJobs.IndexDocumentJob.ExecuteAsync(IndexDocumentJobArgs args) The job retries until TryCount = 10, then is abandoned. The DataSource row exists in the DB and the blob exists in Azure — only the path the indexer resolves is wrong.
- Steps to reproduce the issue:
BackgroundJobExecuter.GetJobArgsTenantId(object jobArgs) in Volo.Abp.BackgroundJobs.Abstractions:
protected virtual Guid? GetJobArgsTenantId(object jobArgs) { return jobArgs switch { IMultiTenant multiTenantJobArgs => multiTenantJobArgs.TenantId, _ => CurrentTenant.Id }; } AbpBackgroundJobs table has no TenantId column (by design — BackgroundJobRecord does not implement IMultiTenant). So the only mechanism to carry tenant from enqueue → execute is the args class implementing IMultiTenant.
We inspected the queued args in AbpBackgroundJobs.JobArgs for our failing job:
{"dataSourceId":"c4b5d4f3-a627-e1f5-a9ab-3a2168f8944b"} — no tenantId field. Therefore IndexDocumentJobArgs does not implement IMultiTenant. The executer falls into the _ => CurrentTenant.Id branch on the worker thread (host context, CurrentTenant.Id == null), so ExecuteAsync runs as host and the blob naming normalizer omits the tenants/{tenantId}/ prefix.
2 Answer(s)
-
0
- Your analysis is correct: ABP background jobs execute under the tenant determined by
BackgroundJobExecuter.GetJobArgsTenantId(jobArgs), and when the args don’t implementIMultiTenant, the executer falls back toCurrentTenant.Id(which is typicallynullon the worker), so the job runs in host context. - With Azure Blob Storing, the blob name is tenant-scoped by default: it prefixes the blob path with
tenants/<tenant-id>when the current tenant is notnull. So running the indexing job in host context makes it look under the wrong blob key.
What to do (workaround you can apply now)
- Ensure the job args carries the TenantId by implementing
IMultiTenantand includingTenantIdin the serialized args. - Enqueue the job with TenantId populated from the current tenant at upload time.
Example (conceptual fix):
using System; using Volo.Abp.MultiTenancy; public class IndexDocumentJobArgs : IMultiTenant { public Guid? TenantId { get; set; } public Guid DataSourceId { get; set; } }When enqueueing:
await _backgroundJobManager.EnqueueAsync( new IndexDocumentJobArgs { TenantId = _currentTenant.Id, DataSourceId = dataSourceId } );This makes
BackgroundJobExecuterswitch to that tenant before callingExecuteAsync, so the blob provider will resolve the correcttenants/<tenantId>/...prefix.If you can’t change the args type (alternate workaround)
Wrap the job execution with an explicit tenant change (only works if you can determine tenantId from DB by
DataSourceIdwithout requiring tenant context, e.g., host-visible table or query with disabled filter):using (_currentTenant.Change(tenantId)) { // read blob + index }Notes / expectation
Given how ABP blob naming works, the job must run under the same tenant that uploaded the blob (or you must disable multi-tenancy for that blob container, which would change the storage layout and isolation semantics).
References
- Azure blob name calculation (tenant prefix rules): https://abp.io/docs/latest/framework/infrastructure/blob-storing/azure
- Changing tenant context (
ICurrentTenant.Change): https://abp.io/docs/latest/framework/architecture/multi-tenancy#change-the-current-tenant
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Your analysis is correct: ABP background jobs execute under the tenant determined by
-
0
Hi,
Thanks for reporting this issue.
You are right that AI Management is not intended to work as a tenant-scoped feature. The problem was caused by the
workspace-data-sourcesblob container still using tenant-aware blob storage behavior.We have confirmed and fixed this issue by configuring that container as shared instead of tenant-scoped and it'll be published in the next patch release.
As a temporary workaround on your project, you can configure the same container as shared in one of your application's module
ConfigureServicesmethods:using Volo.Abp.BlobStoring; using Volo.AIManagement; public override void ConfigureServices(ServiceConfigurationContext context) { Configure<AbpBlobStoringOptions>(options => { options.Containers.Configure<WorkspaceDataSourceBlobContainer>(container => { container.IsMultiTenant = false; }); }); }Please note that this changes the resolved blob path from tenant-scoped to shared/host-scoped. So if you already uploaded documents under
tenants/<tenant-id>/..., those existing files may need to be re-uploaded after applying the workaround.This fix will be included in the next patch release.
Best regards,
ABP Support Team
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)