Workflow Integration

◷ Reading Time: 7 minutes

Execution

When a generic flow is used, the Run method on RuntimeEngine can be called and it executes the flow until it reaches the End node. In a Workflow, you can also Resume, which means you send a signal using the Resume method and the workflow instance will be loaded back and continues execution based on the signal that is sent.

Run

The engine runs the workflow from its initial state (i.e., Start node). When a workflow is run, there will be a Workflow Instance associated with the model. This instance of the workflow model will go through different states:

  1. Active: When the engine is transitioning from one node to another
  2. Waiting: When the instance reaches a node that requires an external interaction
  3. Fault: When execution is finished because something has gone wrong during the execution
  4. Completed: When execution is finished successfully.

Resume

To resume a workflow, the WorkflowExecutionContext must be maintained. This can be as simple as holding the object in memory, but for long-running processes and business transactions this must be maintained in durable storage (e.g., database, blob storage, etc.).

Signals

A Signal is simply an object of an IReceiverSignal which specifies the Title and Category of a Task. It can match a Task by using one of the combinations shown below:

  1. Title
  2. Title, Category
  3. Title, Category, NodeName

Or you can implement a custom Match method when required.

Managers

A workflow uses managers to enable advanced capabilities (i.e., automatic timeout, human workflow, long-running process, etc.). Also, the manager allows you to inject your custom behavior into a workflow for any type of customization. There are two types of managed objects:

  1. Event Handlers
  2. Services

Event handlers and Services can be registered on the engine and there are some handlers on manager registry by default. Each of these custom behaviors can be registered on WorkflowManager.

Event handlers are objects that allow workflow customization based on workflow events. Services are objects that allow you to inject a custom behavior and access them during workflow execution on different steps of the workflow model.

Events

When a workflow is executed, it raises events on state changes. These events give your application an opportunity to manage the state of the workflow instance.

Below is the list of events:

  • PreStart: Before a workflow is started
  • PostEnd: After a workflow is finished (execution is completed)
  • PreResume: Before a workflow, the instance is resumed
  • PreStore: Before a workflow, the instance is being stored
  • PostStore: After a workflow, the instance is stored
  • HandlerAdded: When custom event handler has been added to the WorkflowEventsManager

Event Handlers

Timeout

  1. ExpiredReceiversManager: Automatically sends a signal for a Timeout task when its configured time is expired.

Long-running process

A long-running business transaction needs to maintain the context to resume the workflow instance when a signal is received. Then it needs to store the context to durable storage when workflow goes into a waiting state. The behaviors below are used to manage this scenario:

  1. IWorkflowInstanceOwnerManager: When a workflow is about to resume, the actor can take acquire a lock and resume the workflow. This means no one else can resume or interact with the workflow until it is completed or it goes into a Waiting state again.
  2. IWorkflowInstanceStateManager: When a workflow instance is going to go to a Waiting state, it should store its context to durable storage. This interface defines the behaviors of managing the state of context in the storage.
  3. IInstanceIdentity: This defines a workflow address to your workflow model. When a workflow instance context is stored, this interface allows you to associate the context to the actual workflow model so you can distinguish between different contexts in the storage and identify them when required.
  4. NewWorkflowInstanceIdWriter: Writes a new workflow into the configured storage and retrieves the WorkflowInstanceId and sets it on the context. This enables all workflow instances to have the WorkflowInstanceId available.

To enable the long-running workflow, you need to:

  1. have an MSSQL installed
  2. create required tables
  3. use EnableLongRunningProcess method to enable long-running behavior

Human Task

  1. TasksHandler: inject an instance of TaskService to the workflow instance to manage Human Task behavior
  2. ITaskService: Allows implementing the complex human task behaviors (i.e., expiration, delegation, escalation, WorkItem management, etc.).

Services

Enabling a long-running process

When an instance of RuntimeEngine is created (e.g., engine), then by calling EnableLongRunningProcess on Workflow you can enable the long-running processes. Just make sure you have set up the required database tables.

Your application may manage only one workflow model or may deal with different workflow models.

Single Workflow Model

public void LoadLongRunningWorkflow()
{
  var cnnString = ConfigurationManager.ConnectionStrings["ProcessStateStore"].ConnectionString;
  var config = new LongRunningProcessConfig(
       cnnString, // connection string to the database to manage contexts and timers automatically
       );
 
  engine.Workflow.EnableLongRunningProcess(config);
}

Multiple Workflow Models

When your application deals with multiple workflow models, it must provide an identity for each workflow model. This identity is created based on the root attributes of the Workflow models:

  1. name
  2. namespace
  3. version

This identity is created and set on the engine level automatically when EnableLongRunningProcess is called. Also, it can be accessed by the Address property of the engine.

class YourWorkflowApp
{
  public void LoadLongRunningWorkflow()
  {
   var cnnString = ConfigurationManager.ConnectionStrings["ProcessStateStore"].ConnectionString;
   var config = new LongRunningProcessConfig(
       cnnString, // connection string to the database to manage contexts and timers automatically
       );
 
   engine.Workflow.EnableLongRunningProcess(config);
   // Workflow engine identity
   var address = engine.Workflow.Address;
   // database Id for the workflow address
   var addressId = engine.Workflow.AddressId;
  }
}

Timeout callback

When a Timeout node expires, a workflow can automatically continue the execution. This behavior requires ExpiredReceiversManager to be registered on the WorkflowEventsManager. In a long-running process, this registration is performed as part of enabling the workflow to handle long-running processes. The application can receive a callback when a Timeout expiry occurs. For the callback, you need to set the TimeoutNodeExpiredCallback property on the configuration object (LongRunningProcessConfig).

config.TimeoutNodeExpiredCallback = timeout_node_expired; // callback to your application when a timer is expired

Database scripts

By default FlexRule, supports MSSQL for workflow persistence behaviors. The following database scripts must be run to create the required tables for Workflow management:

  1. Long-running process:
    Database script to manage workflow contexts and timers.
-- This script creates table structures for 
-- storing process state and internal data
-- Please make sure it runs on an existing database
-- Version 1.0

CREATE TABLE [dbo].[Address]( 
 	[RecordId] [uniqueidentifier] NOT NULL PRIMARY KEY,
 	[Name] [nvarchar](150) NOT NULL,
	[Namespace] [nvarchar](255) NULL,
	[Version] [nvarchar](20) NULL,
	[Description] [text] NULL
) 
GO

CREATE UNIQUE NONCLUSTERED INDEX [UNIQUE_NAME_NS_VERSION] ON [dbo].[Address] 
(	[Name] ASC,
	[Namespace] ASC,
	[Version] ASC
)
GO

CREATE TABLE [dbo].[ProcessState](
	[RecordId] [uniqueidentifier] NOT NULL PRIMARY KEY,
	[Context] [image] NULL,
	[Status] [int] NULL,
	[Description] [nvarchar] NULL,
	[Modified] [datetime] NOT NULL,
	[OwnerId] [uniqueidentifier] NULL,
	[OwnedUntil] [datetime2](7) NULL,
	[NextTimer] [datetime2](7) NULL,
	[LastResumed] [datetime2](7) NULL,
	[LastStarted] [datetime2](7) NULL,
	[LastFinished] [datetime2](7) NULL,
	[Error] [text] NULL,
	[AddressId] [uniqueidentifier] NULL,
	[Waiting] [nvarchar](150) NULL,
	[Locked] [bit] NOT NULL
) 
GO

ALTER TABLE [dbo].[ProcessState]  WITH CHECK ADD  CONSTRAINT [FK_ProcessState_Address] FOREIGN KEY([AddressId])
REFERENCES [dbo].[Address] ([RecordId])
GO
Updated on July 16, 2019

Was this article helpful?

Related Articles