Skip to content

fix(runtime): process bookmark queue per tenant scope - #8183

Open
tulrichtrimble wants to merge 1 commit into
elsa-workflows:mainfrom
tulrichtrimble:fix/bookmark-queue-worker-tenant-scope
Open

tulrichtrimble wants to merge 1 commit into
elsa-workflows:mainfrom
tulrichtrimble:fix/bookmark-queue-worker-tenant-scope

Conversation

@tulrichtrimble

Copy link
Copy Markdown

Problem

With multitenancy enabled in Elsa Core (TenantsFeature), enqueued bookmarks
remain stuck indefinitely and fail to resume workflows.

Root Cause: BookmarkQueueWorker.ProcessAsync executes on a background
DI scope without established tenant context. When SetTenantIdFilter installs
EF Core global query filters (on all Entity-derived tables when
TenantsOptions.IsEnabled = true), it compares e.TenantId == dbContext.TenantId.
With null ambient tenant, the filter blocks all rows carrying real TenantId values.

Result: Queue appears empty, bookmark drain silently completes with zero
items processed. Only bookmarks resumed via HTTP request scope (which resolves
tenant context) succeed.

Solution

Modified BookmarkQueueWorker.ProcessAsync to detect multitenancy infrastructure
and iterate tenants when available:

  1. Resolve ITenantsProvider and ITenantScopeFactory from root DI container
  2. If unavailable → fall back to single-scope behavior (backward compatible)
  3. If available:
    • Fetch all active tenants via ITenantsProvider.ListAsync()
    • Process queue once per tenant (including null for tenant-agnostic bookmarks)
    • Create tenant-scoped DI container via ITenantScopeFactory.CreateScope(tenant)
    • Retrieve IBookmarkQueueProcessor from tenant scope
    • Process queue under that tenant's context

This ensures EF Core global filters match the ambient tenant context.

Impact

  • ✅ Fixes bookmark queue drain in multitenancy scenarios
  • ✅ Fixes recurring TriggerBookmarkQueueRecurringTask backstop
  • ✅ Backward compatible: falls back to original behavior when multitenancy not configured
  • ✅ No data model changes required
  • ✅ No breaking API changes

Verification Steps

  1. Enable multitenancy: .UseTenants(f => f.UseTenantsProvider<T>())
  2. Enqueue a bookmark before persistence completes
  3. Trigger BookmarkQueueWorker.ProcessAsync()
  4. Verify bookmark is processed and workflow resumes

Validation

  • Tested with ProM workflow engine (multitenancy enabled)
  • Confirmed compatibility with ITenantAccessor, ITenantScopeFactory, and ITenantsProvider
  • Single clean commit with minimal changes (26 insertions, 3 deletions in one file)

@greptile-apps

greptile-apps Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

PR author is not in the allowed authors list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant