Update multitenancy logic and improve Result handling:#7281
Update multitenancy logic and improve Result handling:#7281sfmskywalker merged 7 commits intorelease/3.6.0from
Result handling:#7281Conversation
- Introduce `TenantsOptions` with `IsEnabled` flag to conditionally apply tenant-specific logic. - Refactor `Result` class to support strongly-typed operations and async handlers. - Implement tenant filters respecting multitenancy enablement. - Enhance error logging for workflow definition addition, upgrading error handling. - Refactor tests and storage drivers to use `IsSuccess` from `Result`.
Greptile OverviewGreptile SummaryThis PR refactors the codebase to improve error handling and add conditional multitenancy support: Key Changes:
Impact: Confidence Score: 3/5
|
| Filename | Overview |
|---|---|
| src/modules/Elsa.Common/Models/Result.cs | New strongly-typed Result monad implementation with async support. Clean implementation with proper generic type support and helper factory methods. |
| src/modules/Elsa.Persistence.EFCore.Common/EntityHandlers/ApplyTenantId.cs | Added TenantsOptions dependency injection and conditional tenant ID application based on IsEnabled flag. Logic refactored with early returns for better readability. |
| src/modules/Elsa.Persistence.EFCore.Common/EntityHandlers/SetTenantIdFilter.cs | Added TenantsOptions check to conditionally apply tenant filters. Added backwards compatibility logic for null TenantId with empty context TenantId. |
| src/modules/Elsa.Workflows.Runtime/Contracts/IWorkflowDefinitionStorePopulator.cs | Changed AddAsync methods to return Result<WorkflowDefinition> instead of WorkflowDefinition directly. Breaking interface change that requires all callers to be updated. |
| src/modules/Elsa.Workflows.Runtime/Services/DefaultWorkflowDefinitionStorePopulator.cs | Implemented Result return types for AddAsync methods with error handling and logging. Uses OnSuccess pattern to handle successful workflow additions and trigger indexing. |
Sequence Diagram
sequenceDiagram
participant Client
participant PopulateStore as DefaultWorkflowDefinitionStorePopulator
participant AddOrUpdate as AddOrUpdateAsync
participant Store as WorkflowDefinitionStore
participant TriggerIndexer
Client->>PopulateStore: PopulateStoreAsync()
loop For each workflow provider
PopulateStore->>PopulateStore: Get workflows from provider
loop For each workflow
PopulateStore->>PopulateStore: Check tenant ID match
alt Tenant matches or is agnostic
PopulateStore->>PopulateStore: AddAsync(workflow)
PopulateStore->>AddOrUpdate: AddOrUpdateAsync()
alt Success
AddOrUpdate->>Store: SaveManyAsync()
AddOrUpdate-->>PopulateStore: Result.Success(definition)
PopulateStore->>PopulateStore: OnSuccess handler
alt Is published and indexTriggers=true
PopulateStore->>TriggerIndexer: IndexTriggersAsync()
end
PopulateStore->>PopulateStore: Add to workflowDefinitions list
else Exception
AddOrUpdate-->>PopulateStore: Result.Failure(exception)
Note over PopulateStore: Error logged, workflow skipped
end
else Tenant mismatch
Note over PopulateStore: Workflow skipped with debug log
end
end
end
PopulateStore-->>Client: List of WorkflowDefinition
Additional Comments (1)
|
There was a problem hiding this comment.
Pull request overview
This pull request refactors the Result class to provide strongly-typed error handling and introduces conditional multitenancy support. The changes move Result from Elsa.Expressions.Models to Elsa.Common.Models, making it generic (Result<T>) with async handler support, while maintaining backwards compatibility through inheritance. Additionally, a new TenantsOptions.IsEnabled flag allows conditional application of tenant-specific logic in EF Core entity handlers.
Changes:
- Refactored
Resultto a genericResult<T>class with async handler methods (OnSuccessAsync,OnFailureAsync) and static factory methods (Success<T>,Failure<T>) - Renamed
Successproperty toIsSuccessacross all usages - Added
TenantsOptions.IsEnabledflag to conditionally enable/disable multitenancy features - Enhanced error logging in workflow definition store population with rich contextual information
- Updated EF Core entity handlers to respect multitenancy enablement flag and added backwards compatibility for null tenant IDs
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/modules/Elsa.Common/Models/Result.cs | New strongly-typed Result class with generic support, async handlers, and factory methods |
| src/modules/Elsa.Expressions/Models/Result.cs | Removed old non-generic Result class (moved to Elsa.Common) |
| src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs | Updated to import Result from Elsa.Common.Models |
| src/modules/Elsa.Workflows.Runtime/Contracts/IWorkflowDefinitionStorePopulator.cs | Changed AddAsync methods to return Result instead of WorkflowDefinition |
| src/modules/Elsa.Workflows.Runtime/Services/DefaultWorkflowDefinitionStorePopulator.cs | Implemented Result-based error handling with detailed logging and async handlers |
| src/modules/Elsa.Workflows.Core/VariableStorageDrivers/WorkflowInstanceStorageDriver.cs | Updated Success to IsSuccess property |
| src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs | Updated Success to IsSuccess and simplified code structure |
| src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/Models.cs | Updated Success to IsSuccess property |
| src/modules/Elsa.Tenants/Options/TenantsOptions.cs | Added IsEnabled property to control multitenancy features |
| src/modules/Elsa.Tenants/Features/TenantsFeature.cs | Sets IsEnabled to true when TenantsFeature is applied |
| src/modules/Elsa.Persistence.EFCore.Common/EntityHandlers/SetTenantIdFilter.cs | Conditionally applies tenant filters based on IsEnabled flag, added backwards compatibility for null TenantId |
| src/modules/Elsa.Persistence.EFCore.Common/EntityHandlers/ApplyTenantId.cs | Conditionally applies tenant IDs based on IsEnabled flag |
| test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Tests.cs | Updated test assertions from Success to IsSuccess |
src/modules/Elsa.Workflows.Runtime/Services/DefaultWorkflowDefinitionStorePopulator.cs
Outdated
Show resolved
Hide resolved
…initionStorePopulator.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…oduce `ValueOrDefault` property for better null support.
…y' into bug/tenancy-backward-compatibilty
…d use it in `DefaultWorkflowRegistry` to ensure operation success.
Fixed via fdda5b1 |
|
@greptile Please review my fixes based on your feedback. |
Greptile OverviewGreptile SummaryThis PR refactors the Key Changes:
Benefits:
Confidence Score: 4/5
|
| Filename | Overview |
|---|---|
| src/modules/Elsa.Common/Models/Result.cs | Added new strongly-typed Result<T> monad with async handlers, ValueOrDefault property, and ThrowIfFailure method for improved error handling. |
| src/modules/Elsa.Tenants/Options/TenantsOptions.cs | Added IsEnabled flag to conditionally apply multitenancy logic throughout the system. |
| src/modules/Elsa.Persistence.EFCore.Common/EntityHandlers/ApplyTenantId.cs | Added multitenancy enablement check to conditionally apply tenant IDs; refactored to early-return pattern. |
| src/modules/Elsa.Persistence.EFCore.Common/EntityHandlers/SetTenantIdFilter.cs | Added multitenancy enablement check and backwards compatibility filter to include records with null TenantId when context TenantId is empty string. |
| src/modules/Elsa.Workflows.Runtime/Services/DefaultWorkflowDefinitionStorePopulator.cs | Refactored to return Result<WorkflowDefinition>, added try-catch with error logging, and used OnSuccess handler in PopulateStoreAsync. |
Sequence Diagram
sequenceDiagram
participant Client
participant DefaultWorkflowRegistry
participant DefaultWorkflowDefinitionStorePopulator
participant WorkflowDefinitionStore
participant TriggerIndexer
participant ApplyTenantId
participant SetTenantIdFilter
Client->>DefaultWorkflowRegistry: RegisterAsync(workflow)
DefaultWorkflowRegistry->>DefaultWorkflowDefinitionStorePopulator: AddAsync(materializedWorkflow)
Note over DefaultWorkflowDefinitionStorePopulator: Checks TenantsOptions.IsEnabled
DefaultWorkflowDefinitionStorePopulator->>DefaultWorkflowDefinitionStorePopulator: AddOrUpdateAsync()
alt Success
DefaultWorkflowDefinitionStorePopulator->>WorkflowDefinitionStore: SaveManyAsync()
WorkflowDefinitionStore->>ApplyTenantId: HandleAsync() [if IsEnabled]
ApplyTenantId-->>WorkflowDefinitionStore: Apply TenantId
WorkflowDefinitionStore->>SetTenantIdFilter: Handle() [if IsEnabled]
SetTenantIdFilter-->>WorkflowDefinitionStore: Apply query filter
WorkflowDefinitionStore-->>DefaultWorkflowDefinitionStorePopulator: WorkflowDefinition
DefaultWorkflowDefinitionStorePopulator->>DefaultWorkflowDefinitionStorePopulator: Result.Success(workflowDefinition)
DefaultWorkflowDefinitionStorePopulator->>TriggerIndexer: IndexTriggersAsync() [if published]
DefaultWorkflowDefinitionStorePopulator-->>DefaultWorkflowRegistry: Result<WorkflowDefinition>
DefaultWorkflowRegistry->>DefaultWorkflowRegistry: result.ThrowIfFailure()
DefaultWorkflowRegistry-->>Client: Success
else Failure
DefaultWorkflowDefinitionStorePopulator->>DefaultWorkflowDefinitionStorePopulator: Log error
DefaultWorkflowDefinitionStorePopulator->>DefaultWorkflowDefinitionStorePopulator: Result.Failure(exception)
DefaultWorkflowDefinitionStorePopulator-->>DefaultWorkflowRegistry: Result<WorkflowDefinition>
DefaultWorkflowRegistry->>DefaultWorkflowRegistry: result.ThrowIfFailure()
DefaultWorkflowRegistry-->>Client: Throws exception
end
src/modules/Elsa.Persistence.EFCore.Common/EntityHandlers/SetTenantIdFilter.cs
Show resolved
Hide resolved
j03y-nxxbz
left a comment
There was a problem hiding this comment.
Backwards compatibility issue seems resolved.
Improvement of error handling is clear and adds value.
…ltWorkflowDefinitionStorePopulator`.
…izeTenantId()` in `DefaultWorkflowDefinitionStorePopulatorTests`.
TenantsOptionswithIsEnabledflag to conditionally apply tenant-specific logic.Resultclass to support strongly-typed operations and async handlers.IsSuccessfromResult.