IResilienceStrategy Abstraction with Category-Based Matching · Issue #6444 · elsa-workflows/elsa-core · GitHub
More Web Proxy on the site http://driver.im/
You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Implement resilience capabilities by introducing a general-purpose IResilienceStrategy abstraction. This abstraction applies to various types of activities (e.g., HTTP requests, email sending, database operations) and allows users to select an appropriate resilience strategy based on activity context through category matching.
Proposed Approach
IResilienceStrategy Abstraction
Define a common IResilienceStrategy interface that all resilience strategies implement.
Ensure that all strategy classes are serializable so that configuration objects (from appsettings.json, a database, etc.) can be deserialized into concrete strategy instances.
Expose public properties on each strategy to allow user configuration. For example, the HTTP resilience strategy could expose the number of retries and a backoff factor (if it’s a retry-type policy).
Category-Based Matching with Attributes
Introduce a [ResilienceCategory("CategoryName")] attribute to annotate both strategy implementations and activities.
Example:
An HTTP-specific resilience strategy implementation would be annotated with [ResilienceCategory("HTTP")].
The SendHttpRequest activity would include a property (e.g., ResilienceStrategyId) annotated with [ResilienceCategory("HTTP")] to ensure that the UI filters and presents only strategies matching the HTTP category.
This mechanism allows the system to dynamically match activities with applicable resilience strategies based on shared tags.
Data Modeling & Configuration
Provide a configuration model (e.g., in appsettings.json or a database) where users can define a list of available strategy definitions.
A sample snippet of appsettings.json could define two configurations of the HTTP resilience strategy—one with 3 retry attempts and another with 10:
Each activity (e.g., SendHttpRequest and SendEmail) will include a ResilienceStrategyId property annotated with the relevant category attribute.
At runtime, using the activity execution context, the selected strategy is retrieved via a strategy service, deserialized from configuration, and then used to wrap the core activity logic.
When no strategy is selected, no resilience strategy is applied.
Only one resilience strategy can be selected per activity.
C# Pseudo Code Examples
usingSystem;usingSystem.Net.Http;usingSystem.Threading.Tasks;usingPolly;usingPolly.Retry;// IResilienceStrategy InterfacepublicinterfaceIResilienceStrategy{stringId{get;}Task<T>ExecuteAsync<T>(Func<Task<T>>action);}// ResilienceCategory attribute for tagging strategies and activity properties[AttributeUsage(AttributeTargets.Class|AttributeTargets.Property,AllowMultiple=false)]publicclassResilienceCategoryAttribute:Attribute{publicstringCategory{get;}publicResilienceCategoryAttribute(stringcategory)=>Category=category;}// HTTP Resilience Strategy Implementation using Polly[ResilienceCategory("HTTP")]publicclassHttpResilienceStrategy:IResilienceStrategy{publicstringId{get;set;}="HttpResilienceStrategy";// Public properties for configurationpublicintRetryCount{get;set;}=3;publicdoubleBackoffFactor{get;set;}=2.0;publicasyncTask<T>ExecuteAsync<T>(Func<Task<T>>action){AsyncRetryPolicy<T>policy=Policy.Handle<Exception>().WaitAndRetryAsync(RetryCount,
retryAttempt =>TimeSpan.FromSeconds(Math.Pow(BackoffFactor,retryAttempt)));returnawaitpolicy.ExecuteAsync(action);}}// Email Resilience Strategy Implementation using Polly[ResilienceCategory("Email")]publicclassEmailResilienceStrategy:IResilienceStrategy{publicstringId{get;set;}="EmailResilienceStrategy";// Public properties for configurationpublicintRetryCount{get;set;}=5;publicintDelaySeconds{get;set;}=1;publicasyncTask<T>ExecuteAsync<T>(Func<Task<T>>action){AsyncRetryPolicy<T>policy=Policy.Handle<Exception>().WaitAndRetryAsync(RetryCount,
retryAttempt =>TimeSpan.FromSeconds(DelaySeconds*retryAttempt));returnawaitpolicy.ExecuteAsync(action);}}// A simple service to retrieve strategies by their IDpublicinterfaceIResilienceStrategyService{IResilienceStrategyGetStrategyById(stringid);}// Simplified Activity Execution Context for service resolutionpublicclassActivityExecutionContext{privatereadonlyIServiceProvider_serviceProvider;publicActivityExecutionContext(IServiceProviderserviceProvider)=>_serviceProvider=serviceProvider;publicTGetService<T>()=>(T)_serviceProvider.GetService(typeof(T));}// Simplified SendHttpRequest activitypublicclassSendHttpRequestActivity{[ResilienceCategory("HTTP")]publicstringResilienceStrategyId{get;set;}publicasyncTask<HttpResponseMessage>ExecuteAsync(ActivityExecutionContextcontext){varstrategyService=context.GetService<IResilienceStrategyService>();IResilienceStrategystrategy=!string.IsNullOrEmpty(ResilienceStrategyId)?strategyService.GetStrategyById(ResilienceStrategyId):null;Func<Task<HttpResponseMessage>>action=async()=>{using(varhttpClient=newHttpClient()){returnawaithttpClient.GetAsync("https://example.com/api/resource");}};returnstrategy!=null?awaitstrategy.ExecuteAsync(action):awaitaction();}}// Simplified SendEmail activitypublicclassSendEmailActivity{[ResilienceCategory("Email")]publicstringResilienceStrategyId{get;set;}publicasyncTaskExecuteAsync(ActivityExecutionContextcontext){varstrategyService=context.GetService<IResilienceStrategyService>();IResilienceStrategystrategy=!string.IsNullOrEmpty(ResilienceStrategyId)?strategyService.GetStrategyById(ResilienceStrategyId):null;Func<Task<bool>>action=async()=>{awaitEmailService.SendEmailAsync("recipient@example.com","Subject","Body");returntrue;};if(strategy!=null)awaitstrategy.ExecuteAsync(action);elseawaitaction();}}// Dummy EmailService for demonstration purposespublicstaticclassEmailService{publicstaticTaskSendEmailAsync(stringrecipient,stringsubject,stringbody){// Email sending implementation goes herereturnTask.CompletedTask;}}
Conclusion
This feature will provide a flexible, extensible, and configuration-driven approach to applying resilience strategies across different types of activities in Elsa. By leveraging a common IResilienceStrategy interface, using category-based matching via attributes, and integrating Polly for proactive and reactive resilience policies, the system ensures that only appropriate resilience strategies are presented for each activity, thereby simplifying configuration and enhancing overall reliability.
The text was updated successfully, but these errors were encountered:
sfmskywalker
changed the title
General-Purpose IRetryStrategy Abstraction with Category-Based Matching
IRetryStrategy Abstraction with Category-Based Matching
Feb 24, 2025
sfmskywalker
changed the title
IRetryStrategy Abstraction with Category-Based Matching
IResilienceStrategy Abstraction with Category-Based Matching
Feb 24, 2025
Implement resilience capabilities by introducing a general-purpose
IResilienceStrategy
abstraction. This abstraction applies to various types of activities (e.g., HTTP requests, email sending, database operations) and allows users to select an appropriate resilience strategy based on activity context through category matching.Proposed Approach
IResilienceStrategy Abstraction
IResilienceStrategy
interface that all resilience strategies implement.Category-Based Matching with Attributes
[ResilienceCategory("CategoryName")]
attribute to annotate both strategy implementations and activities.[ResilienceCategory("HTTP")]
.SendHttpRequest
activity would include a property (e.g.,ResilienceStrategyId
) annotated with[ResilienceCategory("HTTP")]
to ensure that the UI filters and presents only strategies matching the HTTP category.Data Modeling & Configuration
Usage in Activities
SendHttpRequest
andSendEmail
) will include aResilienceStrategyId
property annotated with the relevant category attribute.C# Pseudo Code Examples
Conclusion
This feature will provide a flexible, extensible, and configuration-driven approach to applying resilience strategies across different types of activities in Elsa. By leveraging a common
IResilienceStrategy
interface, using category-based matching via attributes, and integrating Polly for proactive and reactive resilience policies, the system ensures that only appropriate resilience strategies are presented for each activity, thereby simplifying configuration and enhancing overall reliability.The text was updated successfully, but these errors were encountered: