Node Results
Result types returned by node executors during workflow execution.
Overview
Node executors return NodeResult to indicate execution outcome and control flow. The engine uses these results to determine the next steps in workflow execution.
NodeResult Hierarchy
ContinueResult
Class Signature
Properties
| Property | Type | Default | Description |
|---|---|---|---|
targetNodeIds | List<String> | -- | Target node IDs to continue to |
output | Map<String, dynamic> | const {} | Data to merge into workflow output |
effects | List<WorkflowEffect> | const [] | Side effects to process before continuing |
Indicates successful execution with continuation to target node(s).
Usage Examples
Single target:
return ContinueResult.single('processData',
output: {'validated': true},
);Multiple targets (parallel execution):
return ContinueResult.all(['sendEmail', 'sendSms'],
output: {'notificationStarted': true},
);With effects:
return ContinueResult.single('nextNode',
output: {'processed': true},
effects: [
const CancelUserTasksEffect(),
RecordEventEffect(event: WorkflowEvent.custom(...)),
],
);WaitForSignalResult
Class Signature
Properties
| Property | Type | Default | Description |
|---|---|---|---|
signalName | String | -- | Name of signal to wait for |
timeout | Duration? | -- | Optional timeout duration |
Pauses workflow execution until an external signal is received.
Usage Examples
Wait for external event:
return WaitForSignalResult(
signalName: 'payment_confirmation',
);Wait with timeout:
return WaitForSignalResult(
signalName: 'payment_confirmation',
timeout: Duration(hours: 1),
);WaitForUserTaskResult
Class Signature
Properties
| Property | Type | Default | Description |
|---|---|---|---|
signalName | String | -- | Signal to wait for (inherited) |
timeout | Duration? | -- | Optional timeout (inherited) |
config | UserTaskConfiguration | -- | User task configuration |
effects | List<WorkflowEffect> | const [] | Effects to apply before creating the user task |
Creates a user task and waits for completion. Extends WaitForSignalResult.
UserTaskConfiguration
Class Signature
Usage Example
return WaitForUserTaskResult(
signalName: 'approval_decision',
config: UserTaskConfiguration(
title: 'Review Expense Report',
schemaType: 'approval',
assignedToRoleId: 'managers',
priority: UserTaskPriority.high,
input: {'expenseId': expenseId},
),
);With Effects (Cancel Previous Tasks)
return WaitForUserTaskResult(
signalName: 'revision_request',
config: UserTaskConfiguration(
title: 'Revise Document',
schemaType: 'revision',
assignedToUserId: submitterId,
),
// Cancel any pending approval tasks before creating revision task
effects: [
const CancelUserTasksEffect(),
],
);CompleteWorkflowResult
Class Signature
Properties
| Property | Type | Default | Description |
|---|---|---|---|
output | Map<String, dynamic> | const {} | Final workflow output |
Indicates workflow has completed successfully.
Usage Example
return CompleteWorkflowResult(
output: {
'result': 'approved',
'completedAt': DateTime.now().toIso8601String(),
},
);FailWorkflowResult
Class Signature
Properties
| Property | Type | Default | Description |
|---|---|---|---|
errorType | ErrorType | -- | Error category (enum) |
message | String | -- | Human-readable message |
isRetryable | bool | false | Whether retry might succeed |
details | Map<String, dynamic>? | -- | Additional error context |
Indicates workflow failed with an error.
ErrorType Enum
enum ErrorType {
validation, // Invalid input/configuration
timeout, // Operation timed out
activity, // Activity execution failed
condition, // Gateway condition evaluation failed
internal, // Internal engine error
cancelled, // Operation was cancelled
}Usage Examples
Validation error:
return FailWorkflowResult.validation(
'Required field missing: entityId',
details: {'field': 'entityId'},
);Timeout error (retryable):
return FailWorkflowResult.timeout(
'Payment gateway timeout',
details: {'gateway': 'stripe', 'attemptNumber': 2},
);Custom error:
return FailWorkflowResult.custom(
errorType: ErrorType.activity,
message: 'Task execution failed',
isRetryable: true,
details: {'taskId': taskId},
);TaskResult
Result types returned specifically by task executors.
TaskResult Hierarchy
TaskSuccess
Class Signature
Properties
| Property | Type | Default | Description |
|---|---|---|---|
effects | List<WorkflowEffect> | -- | Side effects to apply after task completion |
output | Map<String, dynamic> | -- | Computed: merged output from all SetOutputEffects |
outputPortId | String? | -- | Computed: port ID from RouteToPortEffect (if any) |
Usage
Future<TaskResult> execute(ExecutionContext context) async {
final result = await processData(context.input);
return TaskSuccess([SetOutputEffect(output: {
'processedItems': result.items.length,
'totalValue': result.totalValue,
'processedAt': DateTime.now().toIso8601String(),
})]);
}With Effects
Future<TaskResult> execute(ExecutionContext context) async {
final result = await processData(context.input);
return TaskSuccess([
SetOutputEffect(output: {'processed': true}),
// Cancel pending user tasks
const CancelUserTasksEffect(),
// Record audit event
RecordEventEffect(
event: WorkflowEvent.custom(
instanceId: context.workflowInstanceId,
nodeId: context.nodeId,
eventType: 'data_processed',
data: {'itemCount': result.items.length},
),
),
]);
}TaskFailure
Class Signature
ErrorType Enum
enum ErrorType {
validation, // Invalid input/configuration
timeout, // Operation timed out
activity, // Activity execution failed
condition, // Gateway condition evaluation failed
internal, // Internal engine error
cancelled, // Operation was cancelled
}Usage
Future<TaskResult> execute(ExecutionContext context) async {
// Use get<T> for previous node output
final userId = context.get<String>('userId');
if (userId == null) {
return TaskFailure(
errorType: ErrorType.validation,
message: 'userId is required',
);
}
try {
final user = await userService.findById(userId);
if (user == null) {
return TaskFailure(
errorType: ErrorType.validation,
message: 'User not found: $userId',
);
}
return TaskSuccess([SetOutputEffect(output: {'user': user.toJson()})]);
} on TimeoutException {
return TaskFailure(
errorType: ErrorType.timeout,
message: 'User service timeout',
isRetryable: true,
);
} catch (e, st) {
return TaskFailure(
errorType: ErrorType.internal,
message: 'Unexpected error: $e',
details: {'stackTrace': st.toString()},
);
}
}Conversion
Task executors return TaskResult, which the engine converts to NodeResult:
// Conceptual - internal engine logic
if (taskResult is TaskSuccess) {
// Success continues to next node(s) via edges
return ContinueResult.single(nextNodeId, output: taskResult.output);
}
if (taskResult is TaskFailure) {
// Failure fails the workflow
return FailWorkflowResult(
errorType: taskResult.errorType,
message: taskResult.message,
details: taskResult.details,
isRetryable: taskResult.isRetryable,
);
}Best Practices
1. Return Specific Errors
// Good: Specific error type
return TaskFailure(
errorType: ErrorType.validation,
message: 'Amount must be positive',
code: 'INVALID_AMOUNT',
);
// Avoid: Generic error
return TaskFailure(
errorType: ErrorType.internal,
message: 'Error occurred',
);2. Include Context
return TaskFailure(
errorType: ErrorType.activity,
message: 'API call failed',
details: {
'endpoint': '/api/orders',
'statusCode': response.statusCode,
'responseBody': response.body,
},
);3. Mark Retryable Appropriately
// Retryable: Transient failures
return TaskFailure(
errorType: ErrorType.timeout,
isRetryable: true,
);
// Not retryable: Permanent failures
return TaskFailure(
errorType: ErrorType.validation,
isRetryable: false,
);4. Return Focused Output
// Good: Only necessary data
return TaskSuccess([SetOutputEffect(output: {
'orderId': order.id,
'status': order.status,
})]);
// Avoid: Dumping entire objects
return TaskSuccess([SetOutputEffect(output: order.toJson())]); // 50+ fieldsWorkflowEffect
Effects allow executors to declaratively request side effects without directly calling mutation methods. This keeps executors pure and testable.
Common Effects
| Effect | Description |
|---|---|
SetOutputEffect | Set or merge output data |
CancelUserTasksEffect | Cancel pending user tasks |
RecordEventEffect | Record workflow event |
UpdateStatusEffect | Update workflow status |
CreateTokensEffect | Create new tokens for nodes |
See Workflow Effects for the complete reference.
See Also
- Task Executors - Executor implementation
- Workflow Effects - Effect types reference
- Error Handling - Error patterns
- Node Executors - Executor architecture