# FlowDrop Workflow Executor

Enables executing FlowDrop workflows from within other workflows, with sync and async execution modes.

This module is now stable. Some internal classes are marked `@internal` and are not covered by backward compatibility promises. See the [BC Policy](../../docs/reference/api/bc-policy.md) for details.

## Which surface should I use?

Two surfaces, pick by intent:

| Need | Use | Notes |
|------|-----|-------|
| Target workflow known at **design time** — drag onto canvas with typed inputs/outputs | **`WorkflowNode` derivative** (`workflow:<id>`) | Schemas come from the target workflow's declared FlowDrop Schema. One derivative is generated per workflow. |
| Target workflow chosen at **runtime** (`workflow_id` parameter) — multi-tenancy, A/B routing, data-driven dispatch | **`WorkflowExecutor`** plugin | Opaque `{outputs: {...}}` shape — caller doesn't know the target until execution. |

Both delegate to `WorkflowExecutionServiceInterface::execute()`, so recursion
depth (5), circular-reference detection, and queue dispatch are shared. Neither
replaces the other.

### `WorkflowNode` (typed, design-time)

Each `FlowDropWorkflow` config entity is automatically exposed as a
`workflow:<id>` `FlowDropNodeProcessor` derivative. Its input ports are the
target workflow's `input_ports` exposure map; output ports come from its
`output_ports`. Sub-workflow execution is synchronous by default; pass
`__execution_mode__: job_async` to dispatch via queue and have the parent
workflow pause on an `InterruptType::WorkflowExecution` interrupt until the
sub-pipeline's `PipelineCompletedEvent` fires.

### `WorkflowExecutor` (opaque, runtime dispatch)

Documented below — unchanged from earlier releases.

## Service

### WorkflowExecutionServiceInterface

**Service ID:** `flowdrop_workflow_executor.service`

```php
use Drupal\flowdrop_workflow_executor\Service\WorkflowExecutionServiceInterface;
use Drupal\flowdrop_workflow_executor\Enum\WorkflowExecutionMode;

$service = \Drupal::service('flowdrop_workflow_executor.service');

// Synchronous - blocks until complete
$result = $service->execute($workflow, $inputData, WorkflowExecutionMode::Job);

// Async - returns immediately with session ID
$result = $service->execute($workflow, $inputData, WorkflowExecutionMode::JobAsync);

// Fire & forget - queued for cron processing
$result = $service->execute($workflow, $inputData, WorkflowExecutionMode::JobFireForget);

// Retrieve async results later
$result = $service->getResults($sessionId, $waitForCompletion, $timeout);
$service->isComplete($sessionId): bool;
$service->getStatus($sessionId): WorkflowExecutionStatus;
```

### Execution Modes

| Enum Case | Behavior |
|-----------|----------|
| `WorkflowExecutionMode::Job` | Blocks until workflow completes or times out |
| `WorkflowExecutionMode::JobAsync` | Returns session ID immediately for later retrieval |
| `WorkflowExecutionMode::JobFireForget` | Queues for cron processing, no result retrieval |

## DTO

### WorkflowExecutionResult

```php
$result->isSuccess(): bool;
$result->getStatus(): WorkflowExecutionStatus;
$result->getSessionId(): string;
$result->getOutputs(): array;
$result->getErrorMessage(): string;
$result->getExecutionTimeMs(): int;
$result->toArray(): array;
```

## Node Processors

### Workflow Executor (`workflow_executor`)

Executes a child workflow from within a parent workflow. Parameters: `workflow_id`, `input_data`, `execution_mode`, `timeout`.

### Workflow Results Retriever (`workflow_results_retriever`)

Retrieves results from an async workflow execution. Parameters: `session_id`, `wait_for_completion`, `timeout`.

## Safety Features

- Maximum recursion depth: 5 levels
- Circular reference detection
- Execution chain tracking via session metadata
