Flow Studio
Approval State Tracking
Per-actor decisions are stored in Process_ApprovalDecisions. After each decision is recorded, the ApprovalStateTracker evaluates whether consensus has been reached.
Database Table: Process_ApprovalDecisions
CREATE TABLE Process_ApprovalDecisions (
Id UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
TenantId NVARCHAR(100) NOT NULL,
ExecutionId NVARCHAR(100) NOT NULL,
NodeId NVARCHAR(100) NOT NULL,
ActorId NVARCHAR(100) NOT NULL,
Decision TINYINT NOT NULL, -- 1=Approved, 2=Rejected
Comment NVARCHAR(2000) NULL,
DecidedAt DATETIMEOFFSET NOT NULL DEFAULT GETUTCDATE(),
CONSTRAINT UQ_ApprovalDecision UNIQUE (ExecutionId, NodeId, ActorId)
);
Decision States
| State | Meaning |
|---|---|
| Pending | Actor has been assigned a HIL task but has not yet responded (no row in Process_ApprovalDecisions yet) |
| Approved | Actor submitted an Approved decision — row exists with Decision=1 |
| Rejected | Actor submitted a Rejected decision — row exists with Decision=2 |
| Cancelled | Actor's task was cancelled because consensus was already reached by others |
Consensus Evaluation Flow
1
Actor submits decision
POST /api/approvals/{taskId}/decide — writes a row to Process_ApprovalDecisions.
2
ApprovalStateTracker.EvaluateAsync()
Reads all decision rows for this (ExecutionId, NodeId). Applies the strategy logic.
3a
Consensus reached → resume
IWorkflowContinuationOrchestrator.ContinueAsync() is called. Remaining HIL tasks are cancelled.
3b
Not yet → wait
No action. The execution remains suspended. Other actors' tasks stay open.
Accessing Approval State from Executors
// In a downstream executor, read approval decisions from execution memory
var approvalOutput = ctx.ExecutionMemory.GetNodeOutput<ApprovalNodeOutput>("approvalNode1");
// approvalOutput contains:
// .AggregateDecision — Approved | Rejected
// .Decisions — List<ActorDecision>: actorId, decision, decidedAt, comment
// .Strategy — the strategy used
// .CompletedAt — when consensus was reached