Portal Community

The Full Interface

// BizFirst.Ai.ProcessEngine.Domain/Node/Interfaces/IProcessElementExecution.cs

public interface IProcessElementExecution
{
    /// Execute this node with the given context and return a result.
    Task<NodeExecutionResult> ExecuteAsync(
        NodeExecutionContext nodeExecutionContext,
        CancellationToken cancellationToken = default);

    /// Validate configuration before the workflow runs (pre-flight check).
    Task<ValidationResult> ValidateAsync(
        ProcessElementValidationContext validationContext,
        CancellationToken cancellationToken = default);

    /// Handle an exception that occurred during ExecuteAsync.
    Task<NodeExecutionResult> HandleErrorAsync(
        ProcessElementExecutionContext executionContext,
        Exception error,
        CancellationToken cancellationToken = default);

    /// Release resources after execution (successful or failed).
    Task CleanupAsync(
        ProcessElementExecutionContext executionContext,
        CancellationToken cancellationToken = default);
}

Method Responsibilities

MethodCalled WhenYour Responsibility
ExecuteAsync Engine reaches this node during execution Implement your node's logic here. Must return NodeExecutionResult.
ValidateAsync Designer validates the workflow before saving or running BaseNodeExecutor handles this — parses config and calls settings.Validate(). Override settings.Validate() for custom rules.
HandleErrorAsync An unhandled exception is thrown in ExecuteAsync BaseNodeExecutor.ErrorHandler handles this — routes to error port or rethrows. Rarely overridden.
CleanupAsync After execution completes (success or failure) No-op by default in BaseNodeExecutor. Override if you hold resources (DB connections, file handles).

TypeCode Property

The interface does not declare a TypeCode property, but the convention (enforced by the ExecutorRegistry) is that each executor class exposes a public const string NodeTypeName or a public override string ProcessElementTypeCode:

public partial class MyCustomNodeExecutor : BaseNodeExecutor
{
    // Used as the registry key AND as the DB NodeType.typeCode
    public const string NodeTypeName = "my-custom-node";

    public override string ProcessElementTypeCode => NodeTypeName;
}
Do Not Implement IProcessElementExecution Directly Always extend BaseNodeExecutor instead. Implementing the interface directly means you must write all the error handling, configuration loading, GuardRails integration, and SignalR event emission yourself. BaseNodeExecutor provides all of this out of the box.