Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Workflow Runtimes #5444

Merged
merged 159 commits into from
Jun 10, 2024
Merged

Refactor Workflow Runtimes #5444

merged 159 commits into from
Jun 10, 2024

Conversation

sfmskywalker
Copy link
Member

@sfmskywalker sfmskywalker commented May 24, 2024

This PR refactors the workflow runtime APIs in a significant way.

Key Areas of focus:

  1. Workflow Invocation via Workflow Clients

    • Targeting a specific instance in a given IWorkflowRuntime implementation, of which there are three:
      • Local: No locking, suitable only for single-node hosting.
      • Distributed Locking: Locking, suitable for clustered hosting but with limited throughput due to distributed locking.
      • Actor Model: Each workflow instance is its own actor instance, suitable for clustered hosting without distributed locking.
        • Can be optimized further to become database-less for maximum throughput, but this is out of scope for this PR. Additional enhancements will be in a separate repo owned by ELSA-X.
        • Distributed cancellation is only supported if a given runtime supports it (only the Actor Model will support this, which might be an extra incentive for users to move towards this model).
  2. Paradigm Shift Towards Sending Stimuli to the System

    • New workflows will start and existing ones will resume when stimuli match triggers and bookmarks associated with workflow definitions and instances.
  3. HTTP Endpoint Workflows

    • Execute "in context" using the IWorkflowRunner directly, ensuring fast execution without marshaling workflow instances to and from workflow runtimes. This means no locking for the distributed locking runtime and no back-and-forth for the Actor model runtime.
  4. WorkflowInbox Store No Longer Used

    • Results in less DB data being written to and read from.

Fixes #5409 #5227 #5254 #5203


This change is Reviewable

The update introduces caching to workflow runtime and workflow management stores to enhance performance. This is achieved by adding decorators for several stores, which cache records to reduce database fetches. Additionally, a signaler for change tokens allows for cache invalidation when changes occur. The MemoryCache feature has also been updated to include Scrutor for decoration and the caching duration can be configured through the new CachingOptions class.
The WorkflowsMiddleware has been extensively refactored to handle HTTP Endpoint bookmarks and triggers. This involves breaking down the InvokeAsync method by extracting parts of its functionality into separate helper methods such as FindTriggersAsync and FindBookmarksAsync. Moreover, Assist with authorization checks, workflow execution within request timeout, and handling of workflow faults has been improved to be more efficient and clearly segmented.
The authorization process in the AuthenticationBasedHttpEndpointAuthorizationHandler class has been updated to use the Workflow context instead of the WorkflowInstanceId string. The AuthorizeHttpEndpointContext model has been correspondingly changed to include a Workflow property, thereby strengthening the link between authorization and specific workflows.
The code adjustments add new FindAsync methods to the trigger and bookmark store contracts as well as all their concrete implementations (MongoDb, Memory and EFCore). These methods support fetching the first record matching a given filter. The adjustments also include minor syntax improvements and the addition of [UsedImplicitly] attributes where needed.
The code was refactored to simplify the flow of handling workflows in the WorkflowsMiddleware class. Specifically, the methods to start and resume a workflow have been extracted to improve code readability. Further, handleErrorMiddlewares was also updated to better manage instances where no valid workflows or base paths are found.
Added IMemoryCache usage in the WorkflowsMiddleware to cache lookup results for workflows and their associated triggers. This will reduce the number of database operations required when searching for workflows, thus improving performance. The cache is maintained for one minute before it is refreshed.
The code has been updated to have a dynamic cache duration for the workflows instead of a hardcoded one minute. By using the CachingOptions service, the cache duration can now be set in the configuration making it more flexible and adaptable to different performance needs.
This commit includes the implementation of IHttpWorkflowsCacheManager for caching of HTTP workflows. New handlers have been added to invalidate cache on workflow updates. Additionally, WorkflowsMiddleware has been renamed to HttpWorkflowsMiddleware.
The refactoring includes deletion of `IndexWorkflowTriggersHandler.cs` and creation of `IndexTriggers.cs` thus revising the workflow trigger indexing approach. Also, revamped the `ITriggerIndexer` interface which now handles deletion of triggers with specific workflow and filter. Furthermore, the caching mechanism in `HttpWorkflowsCacheManager.cs` is modified to handle eviction of workflow definitions and triggers separately boosting its efficiency.
A summary has been added to the 'IndexedWorkflowTriggers' class, providing a brief description. This description outlines that it represents a collection of indexed workflow triggers, promoting clearer understanding for future reference.
This commit separates the memory caching feature from the Elsa.Common module into a distinct Elsa.Caching module. This includes moving and renaming related files, such as the MemoryCacheFeature class and associated dependencies. The references in other modules and in the main solution file have been updated accordingly to include the new Elsa.Caching module.
Introduced a distributed caching feature with extensible change token signal publishing. Updated various cache-related methods to be asynchronous for improved performance and responsiveness. Also updated some workflow identity references for clarity.
This addition includes the implementation of a distributed caching system with MassTransit transport. The changes introduce necessary interfaces and services, new distributed caching feature along with the support for MassTransit as a transport option. Moreover, the instance management feature has been renamed to clustering feature for better clarity.
Queue name construction is adjusted in the RabbitMqServiceBusFeature and AzureServiceBusFeature modules for better organization and readability. MassTransitChangeTokenSignalPublisher is now a singleton service, ensuring the signal publisher can be shared across the application, increasing efficiency and performance. Also, introduced use of DistributedCacheFeature in MassTransitDistributedCacheFeature module for better modularization.
This commit introduces caching to the workflow definition service, improving the performance for retrieving workflow definitions. 4 new classes have been created (`CachingWorkflowDefinitionService`, `EvictWorkflowDefinitionServiceCache`, `WorkflowDefinitionCacheManager`, and `IWorkflowDefinitionCacheManager`), and several existing classes have been updated to support caching. The caching also includes invalidation mechanisms, ensuring data consistency.
In the workflow definition module, the explicit caching functionality related to workflow definition versioning has been removed in favor of a more streamlined approach. Additionally, the manner in which services are registered has been altered. As a result, the caching now directly involves the overall workflow definition rather than individual versions, simplifying the caching logic and potentially improving the performance.
The MassTransitBroker has been updated to Memory from RabbitMq. In addition, the RealTimeWorkflows and UseWorkflowsSignalRHubs features are now enabled in the code. This change will impact how the service communicates and processes real-time requests for workflow operations.
The reformatting involves a list of variable types in the HttpFeature module. Each type now appears on a new line for improved readability, making the code easier to maintain and review.
Unnecessary using directives were deleted across several files in the Elsa.Http module. This simplifies the code and will possibly improve execution speed. Specific deletions include those for Encoding, Unicode, Extensions, Collections.Generic, Linq, Text, and Tasks namespaces.
This commit simplifies the HttpWorkflowsMiddleware class constructor. It removes the intermediary variables `_next` and `_options` and directly uses the passed arguments in the constructor. Now, the `next` and `options` parameters are used directly throughout the middleware.
This refactoring replaces the use of FindWorkflowDefinitionAsync and MaterializeWorkflowAsync with a single method, FindWorkflowAsync. This simplifies the middleware code and likely improves performance by reducing the number of database queries or service calls required to retrieve a workflow.
Simplified the workflow retrieval process in HttpBookmarkProcessor.cs. Replaced FindWorkflowDefinitionAsync and MaterializeWorkflowAsync methods with a single FindWorkflowAsync call. This reduces the complexity and improves efficiency in retrieving workflow.
Removed redundant lines of code to simplify workflow search functionality. This change simplified the FindWorkflowAsync method by directly calling the FindWorkflowAsync function in the workflowDefinitionService, thus increasing code readability and efficiency.
The method for obtaining a workflow in the Endpoint.cs script has been refactored and streamlined. The 'GetWorkflowDefinition' method is replaced by the 'GetWorkflowAsync' method which directly retrieves the workflow, without the intermediate step of materializing the workflow definition. This shortens the code and simplifies the process.
The constructor for InputFunctionsDefinitionProvider has been simplified by removing unnecessary private fields. Services are now directly used in the method instead of being stored in fields. This improves readability and reduces complexity in the class structure.
Simplified the methods for handling workflow and workflow state in the WorkflowInstance class. The refactoring also included some code clean-ups and variable renaming. The new implementation provides better readability and maintainability of the code by reducing unnecessary lines and improving structuring of objects and responses.
IBookmarkManager from ProtoActorWorkflowRuntime.cs file is removed due to its redundant status. Additionally, the "FindAsync" method has been updated to use a cancellation token. Also, annotations were added to the "ExportWorkflowStateAsync" and "ImportWorkflowStateAsync" methods to flag calls to functions that require unreferenced code.
Unused ReSharper directive in the file IndexTriggers.cs was identified and therefore removed. This change makes the code cleaner and easier to read.
The default millisecond timeout for the WaitAsync functions in the ISignalManager interface has been reduced from 5000ms to 1000ms. This change will speed up signal wait times in our testing framework.
Simplified the syntax representation in the SendMesssage activity in the Elsa Azure Service Bus module. The SupportedSyntaxes property now utilizes a more concise array initialization.
The 'Stimulus' property in DispatchResumeWorkflows and DispatchTriggerWorkflowsRequest classes has been removed as it was marked obsolete. The DispatchWorkflowRequestConsumer has been adjusted to only use the 'BookmarkPayload' property. This ensures a cleaner code base and removes potential confusion between the properties.
The method name GetNamedWorkflowGrain in both ProtoActorWorkflowClient and ClusterExtensions has been renamed to GetNamedWorkflowInstanceClient to improve code clarity. This change provides better semantics of what the function is purposed for.
The commit removes the WorkflowGrainSnapshot and WorkflowInstanceGrainSnapshot classes from the Elsa.ProtoActor module. These classes were part of an older architecture and are no longer required.
The _refCount field in the Worker class from the Azure ServiceBus module was unused. To maintain a clean codebase and improve readability, this field has been removed.
The commit includes the deletion of the entire WorkflowInboxMessageRecord class from Elsa.Dapper module. This file was managing various activities related to the workflow inbox messages, such as delivering messages to a workflow instance.
This commit introduces new V3_2 migrations for MySQL, SQLite, PostgreSQL, and SQLServer database providers. Included are `Up` and `Down` migrations, the corresponding Designer files, and specific Alterations and Runtime changes. SqlDbType specifications were also added for each.
@sfmskywalker sfmskywalker mentioned this pull request May 26, 2024
Empty lines were removed between property declarations to improve readability in WorkflowDefinitionFilter. An error where 'filter.IsReadonly' was used instead of 'IsReadonly' was also corrected to ensure proper functionality. Additionally, WorkflowDefinitionFilter was imported in the Delete and Revert endpoint modules of the Elsa.Workflow.Api class to maintain consistency across the codebase.
The MongoUserStore class was previously tagged as an abstract class in the Identity module of Elsa.MongoDb. This update changes the MongoUserStore class from an abstract to a non-abstract (concrete) class to enable direct instantiation.
This commit introduces a new `ForwardedType` attribute to aid in forwarding types to new types when deserializing JSON. Additionally, the existing bookmarks related to workflow runtime activities have been updated. These changes also require modifying the `PolymorphicSerializer` in the Elsa.MongoDb project to handle types using the new `TypeHelper.GetLatestType` method.
@raymonddenhaan
Copy link
Contributor

SonarCloud has found some issues that are worth looking into.

The logger reference used in the catch block of the DefaultTriggerScheduler.cs file was incorrect. This commit corrects it by using the appropriate logger variable for logging any potential cron expression format errors.
This commit refactor the component tests, introduced new interfaces and events related to workflow definition and trigger change token signals. Removed an unused file, DictionaryExtensions.cs and refactored the GetOrAdd method to better handle null values. Some minor changes and improvements were also made in existing files to enhance overall code cleanliness.
@sfmskywalker sfmskywalker merged commit 77a71af into main Jun 10, 2024
3 of 4 checks passed
@sfmskywalker sfmskywalker deleted the perf/5254 branch June 10, 2024 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants