Skip to main content
Matrix42 Self-Service Help Center

Workflow Activities Migration Guide

Adjusting the Workflow Activities for running on the new Matrix42 Worker Engine.

Goal

The SASM starting from version 10.0.0 introduces the new Workflow Engine based on Matrix42 Workers. The new concept includes the possibility to scale the execution of the Workflows on many computers located not only on the intranet but also on the internet (including Cloud).  The new architecture of the Workflow Engine puts additional restrictions to the Workflow Activities implementation to guarantee it runs successfully regardless of the Workflow runs on Application Server or remotely.

Principals

Matrix42 Worker is a dedicated Windows Service process hosted either on Application Server or any other computer in an intranet or even internet. On Workflow execution the Worker resolves dependent assemblies and automatically downloads them from Server. This mechanism can handle the automatic deployment of the Workflow Activities and their dependent assemblies to Worker, BUT it does not deliver Business Components to Worker which keeps running only on Application Server. Therefore you need to review the Custom Activities for referencing Business Components, and if present, replace these references with the Web Service call.

Step 1:  Set Workflow Activity compatible with Matrix42 Workers

You need implicitly set in the Production database a flag ([PLSLBinaryComponentClassBase].[WorkerCompatible]) for each Workflow Activity which indicates the Activity is "compatible" with the Matrix42 Workers Engine. 

update PLSLBinaryComponentClassBase
SET WorkerCompatible = 1
From PLSLBinaryComponentClassBase B
    inner join PLSLComponentClassBase C On C.[Expression-ObjectID] = B.[Expression-ObjectID] AND
    C.Name = '<Name of Custom Activity>'

Step 2: Run Workflow with Custom Activity on Matrix42 Worker

To validate the Workflow Activity is working correctly on Matrix42 Worker, you need to "Set Execution Engine" to Worker for one of the Workflows which uses the Activity.

Make also sure the System configured in Administration Settings (tab Workflows) to use the Matrix42 Worker engine for Worker compatible workflows. 

Start Workflow execution and assure it finished successfully and the targeted Activity was executed. 

If Workflow is part of your Custom Package and could be installed on multiple environments then the package needs to be adjusted to include the information that the Workflow could be executed on Matrix42 Worker. For that the flag [PLSLXamlComponentClassBase].UseWorkflowWorker needs to be set.

Step 3: Using Data Layer operation in Activity

The Workflow Framework provides the approach for working with the Production database fro the Workflow Activities.  Depends on Matrix42 Worker installation case the module transforms the database request directly over the Data Layer (Matrix42 Workers installed in intranet) or triggers REST web service for data operation on the Application Server when the Worker installed on the internet (Cloud or Data Gateway ). Using this practice guarantees the best option is automatically picked depending on the deployment model.

The Workflow Engine infrastructure provides a few components that are dealing with the data and schema operation.  

Interface Namespace Description
IDataReaderProvider Matrix42.Contracts.Platform.Data Provides the basic functions for reading data from the Production database
IDbProvider Matrix42.ServiceRepository.Contracts.Components Provides the functionality for CRUD operations
ISchemaReaderProvider Matrix42.Contracts.Platform.Data Keeps the methods for retrieving schema metadata information

The instances of these components are initialized on Workflow Engine start and could be received over the Dependency Injection mechanism

protected override void Execute(NativeActivityContext context)
{
    var executor = context.GetExtension<IExtensionExecutor>();
    var schemaReader = executor.Get<ISchemaReaderProvider>();
    var dataProvider = executor.Get<IDataReaderProvider>();
    var objectsData = dataProvider.GetDataList("SPSCommonClassBase", "[Expression-ObjectID] AS ObjectID, TypeID AS TypeID",
        string.Format("[Expression-ObjectID] IN ({0})", ids)
    );
}

Step 4: Calling Web API methods from the Workflow Activity

If your Workflow Activity uses resources which present only on Application Server, then it needs to be reworked to use Web Services instead to guarantee the Activity is correctly executed regardless of Matrix42 Worker location it is running on. 

AppFabric vs Matrix42 Workers

Also, you need to take into consideration that meanwhile the AppFabric Workflow Engine is not fully discontinued (does not happen in 2020), depending on the Product Environment configuration the Workflow Activity can be simultaneously executed as on Matrix42 Worker as on AppFabric. Therefore, at least for some period of time, the Activity implementation should consider both cases.

  AppFabric Matrix42 Workers
Hosted Always on Application Server Anywhere (App Server, Intranet, Internet, Cloud)
Using  Business Components or Server Resources
  • Direct Reference
  • Over the WCF Service Layer (generation 2)

Web Service call over Web API Service Layer (generation 3)

Using Datalayer
  • Direct Datalayer Referencing
  • Over IDbProvider, IDataReaderProvider interfaces
  • Over IDbProvider, IDataReaderProvider interfaces
  • Direct Web Service call to Generic Data Service

The Workflow Execution context provides a simple approach to figure out the run-time Workflow Execution engine. The following code snippet demonstrates how to obtain this information from the Activity context. 

using Matrix42.Workflows.Contracts;
using Matrix42.Workflows.Contracts.Process;

protected override void Execute(NativeActivityContext context)
{
    var workerContext = context.GetExtension<IWorkflowContextExtention>()?.CurrentContext as IWorkflowWorkerContext;
    WorkflowEngine engine = workerContext?.Engine ?? WorkflowEngine.AppFabric;
}

The enumeration Matrix42.Workflows.Contracts.Process.WorkflowEngine  keeps the following values:

  1. AppFabric (1) - the Workflow is running on AppFabric Workflow Engine. 
  2. Matrix42 Workers (2)  - the Workflow is running the Matrix42 Worker engine.
  3. Cloud Workers (3) - the Workflow is executing on the Matrix42 Worker hosted in the Cloud (e.g. Microsoft Azure). In general, this option is identical to "Matrix42 Workers", but for some special cases, it could be considered.

Create a Custom Web Service

If the required functionality is not exposed over the standard Web Service, you need to create a custom Web Service. For more details, see Register Custom Web Service

Call a Web Service

The Web Service which already registered in the Solution Builder Web Service Repository can be triggered using the special component for running Web Methods which already properly initialized on Workflow Engine start, and can be retrieved from the container of the component over the Dependency Injection mechanism addressing the interface Matrix42.Http.Client.Contracts.IWebApiClient. The component exposes a few methods which help to generate and send Web Request to Web Server, and then handle the response.

T Run<T>(Guid operationId, Argument[] arguments = null, object data = null, int? lcid = null);
JToken Run(Guid operationId, Argument[] arguments = null, object data = null, int? lcid = null);
void Call(Guid operationId, Argument[] arguments = null, object data = null);

Input arguments:

  • operationId (Guid) - Id of the Web Service operation in the Services Repository (PLSLWebServiceOperation.ID);
  • arguments (Matrix42.Http.Client.Contracts.Argument[]) - list of the operation incoming argument values;
  • data (object) - for POST and PUT requests defines the request body;
  • lcid (Integer) -  Optional. Sets the Locale of the Client;

Response:

  • <T> - The Web  Response is casted to specified .NET Type ;
  • JToken - the raw response  in a form of JSON;

The following code snippet demonstrates how the WebApiClient component can be used for triggering GDIE job on Server

using Matrix42.Http.Client.Contracts;

protected override void Execute(NativeActivityContext context)
{
    var executor = context.GetExtension<IExtensionExecutor>();
    var proxy = executor.Get<IProxyContainer>();
    IWebApiClient client = proxy.GetWebApiClient();
    client.Run(new Guid("c04a51a2-a720-c94c-e965-08d77a3ca264"), null, new
                    {
                        SequenceId = sequenceId,
                        InputFile = @"C:\Temp\data.xml"
                    });
}

 Examples

This section provides a few examples explaining how to migrate WF activities.

"File Exists" Workflow Activity

The activity checks the presence of the file of the Application Server. At the original, it has a very simple implementation as Workflow on AppFabric always running on Application Server

public sealed class FileExists : NativeActivity
{
    public InArgument<string> Path { get; set; }
    public OutArgument<bool> Result { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        string path = context.GetValue(Path);
        context.SetValue(Result, File.Exists(path));
    }
}

 As far as the Matrix42 Worker could be installed remotely the original implementation could not be valid as it will check the File on the Matrix42 Worker computer, not on Application Server. To make this Activity compatible with the Matrix42 Worker includes the following steps:

  1. Try to find  Web Service which implements the logic. See, Web Services: REST API integration
  2. If the Web Service is not present in the Product, then introduce a custom Web Service. For more details, see Register Custom Web Service
  3. Rework the Workflow Activity code and recompile the Workflow Activity. See the code example below.
  4. Mark "File Exists" Workflow Activity as Compatible with Matrix42 Worker. See, Set Workflow Activity compatible with Worker
  5. Ensure the "File Exists" works, as expected on a Matrix42 Worker, installed remotely. See, Run Workflow with Custom Activity on Worker
protected override void Execute(NativeActivityContext context)
{
      string path = context.GetValue(Path);

      bool result;
             
      // Get the current execution engine
      var workerContext = context.GetExtension<IWorkflowContextExtention>()?.CurrentContext as IWorkflowWorkerContext;
      WorkflowEngine engine = workerContext?.Engine ?? WorkflowEngine.AppFabric;

      //Retrieve the WebAPI Client
      var executor = context.GetExtension<IExtensionExecutor>();
      var proxy = executor.Get<IProxyContainer>();
      IWebApiClient client = proxy.GetWebApiClient();
            
      if (engine != WorkflowEngine.AppFabric)
      {
          //Custom Web Service 
           result = client.Run<bool>(new Guid("3E73BB20-4399-40D5-979B-43177FD11713"));
      }
      else
      {
           result = File.Exists(path);
      }

      context.SetValue(Result, result);
}