-
-
Notifications
You must be signed in to change notification settings - Fork 163
Custom Tasks
Custom tasks are a must in a workflow engine and allow systems and applications to interact.
To create a custom task MyTask for example you will need to proceed as follows:
- 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.
- 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..
- 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.
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
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
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
-
Windows:
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;
}
}
}
}
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 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();
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.
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");
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.
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:
- Create your custom task
- Reference your custom task in Wexflow.Server
- Create a workflow using your custom task
- Open Wexflow Manager or the backend and trigger your workflow from there
Copyright © Akram El Assas. All rights reserved.