Fix cross-tenant cache collision in CachingWorkflowDefinitionService (#7318)

* Initial plan

* Fix cross-tenant cache collision in WorkflowDefinitionCacheManager

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
This commit is contained in:
Copilot 2026-02-23 14:11:02 +01:00 committed by GitHub
parent 25575e65af
commit 856f7b40b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,43 +1,44 @@
using Elsa.Caching;
using Elsa.Common.Models;
using Elsa.Common.Multitenancy;
using Elsa.Workflows.Management.Filters;
namespace Elsa.Workflows.Management.Services;
/// <inheritdoc />
public class WorkflowDefinitionCacheManager(ICacheManager cache, IHasher hasher) : IWorkflowDefinitionCacheManager
public class WorkflowDefinitionCacheManager(ICacheManager cache, IHasher hasher, ITenantAccessor tenantAccessor) : IWorkflowDefinitionCacheManager
{
/// <inheritdoc />
public ICacheManager Cache => cache;
/// <inheritdoc />
public string CreateWorkflowDefinitionVersionCacheKey(string definitionId, VersionOptions versionOptions) => $"WorkflowDefinition:{definitionId}:{versionOptions}";
public string CreateWorkflowDefinitionVersionCacheKey(string definitionId, VersionOptions versionOptions) => TenantPrefix() + $"WorkflowDefinition:{definitionId}:{versionOptions}";
/// <inheritdoc />
public string CreateWorkflowDefinitionFilterCacheKey(WorkflowDefinitionFilter filter)
{
var hash = hasher.Hash(filter);
return $"WorkflowDefinition:{hash}";
return TenantPrefix() + $"WorkflowDefinition:{hash}";
}
/// <inheritdoc />
public string CreateWorkflowVersionCacheKey(string definitionId, VersionOptions versionOptions) => $"Workflow:{definitionId}:{versionOptions}";
public string CreateWorkflowVersionCacheKey(string definitionId, VersionOptions versionOptions) => TenantPrefix() + $"Workflow:{definitionId}:{versionOptions}";
/// <inheritdoc />
public string CreateWorkflowVersionCacheKey(string definitionVersionId) => $"Workflow:{definitionVersionId}";
public string CreateWorkflowVersionCacheKey(string definitionVersionId) => TenantPrefix() + $"Workflow:{definitionVersionId}";
/// <inheritdoc />
public string CreateWorkflowFilterCacheKey(WorkflowDefinitionFilter filter)
{
var hash = hasher.Hash(filter);
return $"Workflow:{hash}";
return TenantPrefix() + $"Workflow:{hash}";
}
/// <inheritdoc />
public string CreateWorkflowDefinitionVersionCacheKey(string definitionVersionId) => $"WorkflowDefinition:{definitionVersionId}";
public string CreateWorkflowDefinitionVersionCacheKey(string definitionVersionId) => TenantPrefix() + $"WorkflowDefinition:{definitionVersionId}";
/// <inheritdoc />
public string CreateWorkflowDefinitionChangeTokenKey(string definitionId) => $"WorkflowChangeToken:{definitionId}";
public string CreateWorkflowDefinitionChangeTokenKey(string definitionId) => TenantPrefix() + $"WorkflowChangeToken:{definitionId}";
/// <inheritdoc />
public async Task EvictWorkflowDefinitionAsync(string definitionId, CancellationToken cancellationToken = default)
@ -45,4 +46,10 @@ public class WorkflowDefinitionCacheManager(ICacheManager cache, IHasher hasher)
var changeTokenKey = CreateWorkflowDefinitionChangeTokenKey(definitionId);
await cache.TriggerTokenAsync(changeTokenKey, cancellationToken);
}
private string TenantPrefix()
{
var tenantId = tenantAccessor.TenantId;
return string.IsNullOrEmpty(tenantId) ? string.Empty : $"{tenantId}:";
}
}