Skip to content

Custom Tasks

Akram El Assas edited this page Mar 29, 2024 · 21 revisions

Custom tasks are a must in a workflow engine and allow systems and applications to interact.

General

To create a custom task MyTask for example you will need to proceed as follows:

  1. Create a new class library project in Visual Studio and name it Wexflow.Tasks.MyTask. For .NET, you must target .NET 4.8. For .NET Core, you must target .NET 7.0.
  2. Reference Wexflow dependencies through nuget package manager:
PM> Install-Package Wexflow

Or by using .NET CLI (.NET Core version):

dotnet add package Wexflow

The class library project name must start with Wexflow.Tasks. and the DLL filename must also start with Wexflow.Tasks..

  1. Create a public class MyTask that implements the abstract class Wexflow.Core.Task.

Wexflow.Tasks.MyTask code should look like as follows:

using System.Threading;
using System.Xml.Linq;
using Wexflow.Core;

namespace Wexflow.Tasks.MyTask
{
    public class MyTask : Task
    {
        public MyTask(XElement xe, Workflow wf) : base(xe, wf)
        {
            // Task settings goes here
        }

        public override TaskStatus Run()
        {
            try
            {
                // Task logic goes here

                return new TaskStatus(Status.Success);
            }
            catch (ThreadAbortException)
            {
                throw;
            }
        }
    }
}

Each task returns a TaskStatus object when it finishes performing its job. TaskStatus is composed of the following elements:

public Status Status { get; set; }
public bool Condition { get; set; }
public string SwitchValue { get; set; }

The Status can be one of the followings:

public enum Status
{
  Success,
  Warning,
  Error
}

For example, if a task performs an opetation on a collection of files and if this operation succeeds for all the files then its Status should be Success. Otherwise if this operation succeeds for some files and fails for others then its Status should be Warning. Otherwise if this operation fails for all the files then its Status should be Error.

The Condition property is designed for flowchart tasks. In addition to the Status of the task, a flowchart task returns either true or false after performing its operation.

The Condition property should always be set to false for sequential tasks.

The SwitchValue is designed to be used by Switch flowchart nodes. If you set a value in the SwitchValue property and use this task in a Switch flowchart node, the case corresponding to the value will be executed. Otherwise, if the Default case is set, it will be executed.

You can use the TaskStatus constructor that suits your needs.

To retrieve settings, you can use the following methods:

string settingValue = this.GetSetting("settingName");
string settingValue = this.GetSetting("settingName", defaultValue);
string[] settingValues = this.GetSettings("settingName");

To load a file within a task, you can do it as follows:

this.Files.Add(new FileInf(path, this.Id));

To load an entity within a task, you can do it as follows:

this.Entities.Add(myEntity);

Finally if you finished coding your custom task, compile the class library project and copy the assembly Wexflow.Tasks.MyTask.dll in C:\Program Files\Wexflow\ or in C:\Wexflow\Tasks\ if you use the .NET version. The path of the folder C:\Wexflow\Tasks\ can be configured from tasksFolder setting in the configuration file C:\Wexflow\Wexflow.xml. If you use the .NET Core version, check out the next section.

The custom task namespace and filename must start with Wexflow.Tasks.

Your custom task is then ready to be used as follows:

<Task id="$int" name="MyTask" description="My task description" enabled="true">
    <Setting name="settingName" value="settingValue" />
</Task>

That's it. That's all the things you need to know to start coding your own custom tasks.

To test the custom task, create a new workflow (new XML file) and put the configuration of the custom task in it as follows:

<Workflow xmlns="urn:wexflow-schema" id="99" name="Workflow_MyWorkflow" description="Workflow_MyWorkflow">
	<Settings>
		<Setting name="launchType" value="trigger" /> <!-- startup|trigger|periodic|cron -->
		<Setting name="enabled" value="true" /> <!-- true|false -->
	</Settings>
	<Tasks>
        <Task id="1" name="MyTask" description="My task description" enabled="true">
            <Setting name="settingName" value="settingValue" />
        </Task>
	</Tasks>
</Workflow>

Then, place that XML file in C:\Wexflow\Workflows\.

The workflow will then appear in the list of workflows in Wexflow Manager. You can then launch it from there.

.NET Core

If you use the .NET Core version of Wexflow, once you create your custom task Wexflow.Tasks.MyTask, place Wexflow.Tasks.MyTask.dll in:

  • Windows: C:\Wexflow-netcore\Tasks or .\Wexflow.Server
  • Linux: /opt/wexflow/Wexflow/Tasks or /opt/wexflow/Wexflow.Server
  • macOS: /Applications/wexflow/Wexflow/Tasks or /Applications/wexflow/Wexflow.Server

Referenced Assemblies

If your custom task has referenced assemblies, you must copy them in C:\Program Files\Wexflow\ if you use the .NET version.

If you use the .NET Core version, you must copy them in:

  • Windows: C:\Wexflow-netcore\Tasks or .\Wexflow.Server
  • Linux: /opt/wexflow/Wexflow/Tasks or /opt/wexflow/Wexflow.Server
  • macOS: /Applications/wexflow/Wexflow/Tasks or /Applications/wexflow/Wexflow.Server

Update

If you want to update a custom task, copy paste the custom task and its references as stated in the documentation then restart Wexflow server:

  • .NET: Restart Wexflow Windows Service
  • .NET Core:
    • Windows: .\run.bat
    • Linux: sudo systemctl restart wexflow
    • macOS: dotnet /Applications/wexflow/Wexflow.Server/Wexflow.Server.dll

Suspend/Resume

For .NET Core, if you want to enable suspend/resume for your custom task you need to use this.WaitOne(); in your custom task. Here is an example:

using System.Threading;
using System.Xml.Linq;
using Wexflow.Core;

namespace Wexflow.Tasks.MyTask
{
    public class MyTask : Task
    {
        public MyTask(XElement xe, Workflow wf) : base(xe, wf)
        {
            // Task settings goes here
        }

        public override TaskStatus Run()
        {
            try
            {
                foreach(var file in SelectFiles())
                {
                    // process file...
                    WaitOne();
                }

                return new TaskStatus(Status.Success);
            }
            catch (ThreadAbortException)
            {
                throw;
            }
        }
    }
}

Logging

The following methods are available from the Task class for logging:

public void Info(string msg);
public void InfoFormat(string msg, params object[] args);
public void Debug(string msg);
public void DebugFormat(string msg, params object[] args);
public void Error(string msg);
public void ErrorFormat(string msg, params object[] args);
public void Error(string msg, Exception e);
public void ErrorFormat(string msg, Exception e, params object[] args);

Files

Files can be loaded in a task by calling the methods Add or AddRange:

this.Files.Add(myFile);
this.Files.AddRange(myFiles);

Then the files loaded can be selected in other tasks by their task Id as follows:

<Setting name="selectFiles" value="$taskId" />

To select the files loaded by the running instance of a workflow through the selectFiles settings option, you can do it as follows:

FileInf[] files = this.SelectFiles();

Entities

Entity is an abstract class having the Id of the task as property:

namespace Wexflow.Core
{
    public abstract class Entity
    {
        public int TaskId { get; set; }
    }
}

The entity class is designed to be inherited by other classes such as objects retrieved from a database or a web service or an API or whatever. Then, these objects can be loaded in a task by calling the methods Add or AddRange:

this.Entities.Add(myEntity);
this.Entities.AddRange(myEntities);

Then, the entities loaded can be selected in other tasks by their task Id as follows:

<Setting name="selectEntities" value="$taskId" />

Entities are designed to be used in custom tasks.

To select entities loaded by the running instance of a workflow through the selectEntities settings option, you can do it as follows:

Entity[] entities = this.SelectEntities();

The Entity class could be very useful when working with custom tasks that manipulate objects from a database or Web Services for example.

Shared Memory

Tasks contains a Hashtable that can be used as a shared memory between them.

To add an object to the Hashtable, simply proceed as follows:

this.Hashtable.Add("myKey", myObject);

To retrieve an object from the Hashtable, simply proceed as follows:

var myObject = this.Hashtable["myKey"];

To remove an object from the Hashtable, simply proceed as follows:

this.Hashtable.Remove("myKey");

Designer

To make your custom task MyTask appear in the available tasks in the designer, simply open the file C:\Wexflow\TasksNames.json and add MyTask in it as follows:

[
...
{ "Name": "MyTask", "Description": "MyTask description."},
]

If you use the .NET Core version of Wexflow, you need to edit this file:

  • Windows: C:\Wexflow-netcore\TasksNames.json
  • Linux: /opt/wexflow/Wexflow/TasksNames.json
  • macOS: /Applications/wexflow/Wexflow/TasksNames.json

You must also add the settings by opening the file C:\Wexflow\TasksSettings.json and adding your custom settings as follows:

{
...
"MyTask": [ {"Name": "settingName", "Required": true, "Type": "string", "List": [], "DefaultValue": ""} ],
}

If you use the .NET Core version of Wexflow, you need to edit this file:

  • Windows: C:\Wexflow-netcore\TasksSettings.json
  • Linux: /opt/wexflow/Wexflow/TasksSettings.json
  • macOS: /Applications/wexflow/Wexflow/TasksSettings.json

The available types are:

  • string
  • int
  • bool
  • password
  • list
  • user

user type refers to registered users in Wexflow.

If you choose list type, you have to set the available list options. Here is an example:

{
...
"MyTask": [ {"Name": "protocol", "Required": true, "Type": "list", "List": ["ftp", "ftps", "sftp"], "DefaultValue": ""} ],
}

That's it. MyTask will show up in the designer and when selected its settings will show up as well.

Debugging

To debug custom tasks, you can use logging.

You can also clone Wexflow's repository and open Wexflow.sln in Visual Studio and follow these guidelines to run Wexflow server from source code. Then, you can create your custom task in the solution and debug it. To debug it you have to proceed as follows:

  1. Create your custom task
  2. Reference your custom task in Wexflow.Server
  3. Create a workflow using your custom task
  4. Open Wexflow Manager or the backend and trigger your workflow from there
Clone this wiki locally