DEV Community

Cover image for Bridging Temporal Machine Sagas and Flowable Human Workflows in BIAN Architectures
mountek
mountek

Posted on

Bridging Temporal Machine Sagas and Flowable Human Workflows in BIAN Architectures

Modern core banking platform design presents a structural dilemma: high-frequency distributed systems demand sub-millisecond API execution, eventual consistency, and resilient retries, while corporate governance demands weeks-long human reviews, multi-tiered approvals, and regulatory auditability.

Attempting to resolve both execution profiles with a single orchestration platform inevitably degrades system stability. Forcing BPMN (Business Process Model and Notation) engines to execute low-latency microservice Sagas leads to database state bloat and worker thread starvation. Conversely, using code-first workflow engines to manage multi-week human tasks obscures business visibility, hardcodes organizational approval chains, and compromises audit compliance.

Under the Xenon Architecture Standards, modern banking platform design resolves this tension through a dual-orchestration pattern mapped directly to Banking Industry Architecture Network (BIAN) service domains. This paper evaluates the operational boundaries, data-flow integrations, and failure patterns of pairing Temporal for machine-level distributed transaction Sagas with Flowable for human-in-the-loop business process management.

Architectural Mapping across BIAN Service Domains

The Banking Industry Architecture Network (BIAN) defines standard Service Domains with strict encapsulation boundaries. Each Service Domain exposes functional capabilities through control keys and service operations. However, execution profiles vary drastically across domains.

By establishing an orchestration taxonomy, we assign orchestration responsibility based on state duration, execution throughput, and the presence of human intervention.

BIAN Service Domain Core Capability Dominant Orchestrator Primary Pattern SLA / Latency Target Consistency Model
Payment Execution Automated clearing, ISO20022 message routing Temporal Saga (Compensating) < 200ms Eventual (Deterministic)
Position Keeping Ledger debit/credit updates Temporal Two-Phase Atomic Activity < 50ms Strong Consistency
Consumer Loan Origination End-to-end customer loan application lifecycle Flowable BPMN 2.0 User Task Days to Weeks Workflow State Persisted
Credit Assessment Automated credit scoring & manual underwriting Dual (Hybrid) Flowable drives; Temporal executes Seconds (Auto) / Hours (Manual) Mixed
Customer Onboarding KYC verification, sanctions screening, account setup Dual (Hybrid) Flowable orchestrates stage gates; Temporal executes checks Minutes to Days Eventual
                                   +------------------------------------------+
                                   |         Flowable BPMN Engine             |
                                   |  (Human Workflows & SLA Management)      |
                                   +--------------------+---------------------+
                                                        |
                                            Async gRPC / Event Bus
                                                        |
                                   +--------------------+---------------------+
                                   |         Temporal Engine                  |
                                   |   (Machine Sagas & API Resiliency)       |
                                   +----+---------------+----------------+----+
                                        |               |                |
                                        v               v                v
                               +----------------+ +-----------+ +-----------------+
                               | Payment Engine | | Ledger API| | Screening Engine|
                               +----------------+ +-----------+ +-----------------+

Enter fullscreen mode Exit fullscreen mode

Deep Dive 1: Temporal for Machine-Level Sagas

Temporal provides a developer-centric, code-first durable execution model. It persists the complete stack execution trace of an application, rendering code execution resilient to process crashes, network partitions, and downstream infrastructure outages.

Within the Xenon Architecture framework, Temporal handles machine-to-machine integration patterns where execution must be deterministic, programmatic, and sub-second.

The Saga Pattern in Core Ledger Operations

When executing complex financial movements across isolated microservices (e.g., reserving balance in Position Keeping, checking limits in Risk Management, and posting to General Ledger), distributed ACID transactions are non-viable due to lock contention. Temporal enforces the Saga Pattern by registering explicit compensating actions for every forward transaction step.

Below is an enterprise Go implementation demonstrating a deterministic, fault-tolerant BIAN Payment Saga using Temporal SDK:

package sagas

import (
    "fmt"
    "time"

    "go.temporal.io/sdk/workflow"
)

// PaymentSagaInput holds payload for BIAN Payment Execution
type PaymentSagaInput struct {
    PaymentID        string
    SourceAccount    string
    TargetAccount    string
    Amount           float64
    Currency         string
    CorrelationID    string
}

// PaymentSagaWorkflow orchestrates machine-level execution with strict compensations
func PaymentSagaWorkflow(ctx workflow.Context, input PaymentSagaInput) (err error) {
    options := workflow.ActivityOptions{
        StartToCloseTimeout: 5 * time.Second,
        RetryPolicy: &workflow.RetryPolicy{
            InitialInterval:    100 * time.Millisecond,
            BackoffCoefficient: 2.0,
            MaximumAttempts:    5,
        },
    }
    ctx = workflow.WithActivityOptions(ctx, options)

    var compensations []func(workflow.Context) error
    defer func() {
        if err != nil {
            // Execute compensations in reverse order on failure
            compCtx, _ := workflow.NewDisconnectedContext(ctx)
            for i := len(compensations) - 1; i >= 0; i-- {
                if compErr := compensations[i](compCtx); compErr != nil {
                    workflow.GetLogger(ctx).Error("Compensation failed", "error", compErr)
                }
            }
        }
    }()

    // Step 1: Reserve Funds in Source Account
    var reservationID string
    err = workflow.ExecuteActivity(ctx, ReserveFundsActivity, input.SourceAccount, input.Amount, input.CorrelationID).Get(ctx, &reservationID)
    if err != nil {
        return fmt.Errorf("failed to reserve funds: %w", err)
    }
    // Register Compensation
    compensations = append(compensations, func(cCtx workflow.Context) error {
        return workflow.ExecuteActivity(cCtx, CancelReservationActivity, reservationID, input.CorrelationID).Get(cCtx, nil)
    })

    // Step 2: Perform Real-Time Sanctions Screening
    var passedScreening bool
    err = workflow.ExecuteActivity(ctx, ScreenTransactionActivity, input.PaymentID, input.Amount).Get(ctx, &passedScreening)
    if err != nil || !passedScreening {
        err = fmt.Errorf("sanctions check rejected transaction")
        return err
    }

    // Step 3: Credit Target Account
    var postingID string
    err = workflow.ExecuteActivity(ctx, CreditAccountActivity, input.TargetAccount, input.Amount, input.CorrelationID).Get(ctx, &postingID)
    if err != nil {
        return fmt.Errorf("failed to credit target account: %w", err)
    }

    // Step 4: Finalize Reservation (Commit)
    err = workflow.ExecuteActivity(ctx, FinalizeReservationActivity, reservationID, postingID).Get(ctx, nil)
    if err != nil {
        return fmt.Errorf("failed to finalize balance movement: %w", err)
    }

    return nil
}

Enter fullscreen mode Exit fullscreen mode

Key Technical Advantages of Temporal in Financial Sagas

  • Zero Polling Cost: Event-driven architecture suspends workers while waiting for external system responses without occupying active threads.
  • Transparent Retries: Non-deterministic external failures (e.g., API timeouts) trigger exponential backoffs without polluting business domain state.
  • Exact Execution Replay: System history event sourcing ensures state can be reconstructed precisely during platform disaster recovery events.

Deep Dive 2: Flowable for Human-in-the-Loop Workflows

Flowable implements BPMN 2.0 and CMMN (Case Management Model and Notation) standards. It excels where state persistence spans long periods, processes must adapt dynamically to human input, and compliance requires a clear visual domain map.

Human Approvals in Credit Assessment

In BIAN Credit Assessment, automated scoring engines process standard requests instantaneously. However, applications flagged for risk exceptions must transition to manual underwriting.

Flowable models these long-lived process steps natively using User Tasks, Candidate Groups, and Escalation Timers.

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:flowable="http://flowable.org/bpmn"
             targetNamespace="BIAN/CreditAssessment">

  <process id="loanUnderwritingProcess" name="Loan Underwriting Process" isExecutable="true">

    <startEvent id="startEvent" name="Loan Application Received" />

    <sequenceFlow sourceRef="startEvent" targetRef="callAutomatedScoringSaga" />

    <!-- Java Delegate acting as a client bridge to Temporal Saga -->
    <serviceTask id="callAutomatedScoringSaga" 
                 name="Execute Machine Scoring Saga" 
                 flowable:class="com.xenon.banking.bridge.TemporalSagaDelegate" />

    <sequenceFlow sourceRef="callAutomatedScoringSaga" targetRef="checkScoringDecision" />

    <exclusiveGateway id="checkScoringDecision" name="Approval Decision?" />

    <sequenceFlow sourceRef="checkScoringDecision" targetRef="autoApproveEnd">
      <conditionExpression xsi:type="tFormalExpression">${scoreOutcome == 'AUTO_APPROVED'}</conditionExpression>
    </sequenceFlow>

    <sequenceFlow sourceRef="checkScoringDecision" targetRef="manualUnderwritingTask">
      <conditionExpression xsi:type="tFormalExpression">${scoreOutcome == 'REFER_TO_HUMAN'}</conditionExpression>
    </sequenceFlow>

    <!-- Human Task Assignment -->
    <userTask id="manualUnderwritingTask" 
              name="Manual Credit Review" 
              flowable:candidateGroups="underwriters">
      <documentation>
        Underwriter review required for Application ID: ${applicationId}. Credit Score border case.
      </documentation>
    </userTask>

    <!-- Boundary Timer Event for SLA Escalation -->
    <boundaryEvent id="slaTimer" attachedToRef="manualUnderwritingTask" cancelActivity="false">
      <timerEventDefinition>
        <timeDuration>PT24H</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>

    <sequenceFlow sourceRef="slaTimer" targetRef="escalateToManager" />

    <userTask id="escalateToManager" 
              name="Manager Override Review" 
              flowable:candidateGroups="credit_managers" />

    <sequenceFlow sourceRef="manualUnderwritingTask" targetRef="manualDecisionGateway" />

    <exclusiveGateway id="manualDecisionGateway" name="Approved?" />
    <sequenceFlow sourceRef="manualDecisionGateway" targetRef="approvedEnd">
      <conditionExpression xsi:type="tFormalExpression">${underwriterDecision == 'APPROVED'}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow sourceRef="manualDecisionGateway" targetRef="rejectedEnd">
      <conditionExpression xsi:type="tFormalExpression">${underwriterDecision == 'REJECTED'}</conditionExpression>
    </sequenceFlow>

    <endEvent id="autoApproveEnd" name="Auto Approved" />
    <endEvent id="approvedEnd" name="Manually Approved" />
    <endEvent id="rejectedEnd" name="Application Rejected" />

  </process>
</definitions>

Enter fullscreen mode Exit fullscreen mode

Key Technical Advantages of Flowable for Business Operations

  • Declarative BPMN/CMMN Visualizations: Enables risk, compliance, and auditing teams to inspect and validate business pathways directly using standardised graphical representations.
  • Organizational Hierarchy Awareness: Dynamic resolution of user roles, delegations, managerial escalations, and regional assignment groups.
  • Operational Task APIs: Native capabilities for listing, claiming, reassigning, and completing tasks through enterprise web application interfaces.

The Integration Architecture: Bridging the Dual-Orchestration Gap

The architectural key to Xenon's framework lies in preventing direct, tight coupling between Flowable and Temporal. Flowable must remain agnostic to microservice execution mechanics, and Temporal must not manage long-lived human process state.

We achieve integration via Event-Driven Asynchronous Signals using Apache Kafka or gRPC Bridge Delegates.

+-----------------------------------------------------------------------------------+
| FLOWABLE PROCESS ENGINE                                                           |
|                                                                                   |
|  [BPMN: Start] ---> [ServiceTask: Trigger Saga] ---> [Receive Task: Wait Signal]  |
+-----------------------------------|--------------------------^--------------------+
                                    |                          |
                         1. Async gRPC Execution        4. Signal Execution Callback
                                    |                          |
+-----------------------------------|--------------------------|--------------------+
| INTEGRATION LAYER                 v                          |                    |
|                         +-------------------+      +------------------+           |
|                         | Temporal Client   |      | Signal REST/gRPC |           |
|                         | Dispatcher        |      | Client           |           |
|                         +---------+---------+      +---------^--------+           |
+-----------------------------------|--------------------------|--------------------+
                                    |                          |
                         2. Start Workflow              3. Complete Saga
                                    |                          |
+-----------------------------------|--------------------------|--------------------+
| TEMPORAL ENGINE                   v                          |                    |
|                                                              |                    |
|    [Start Saga Workflow] ---> [Execute Microservices] -------+                    |
+-----------------------------------------------------------------------------------+

Enter fullscreen mode Exit fullscreen mode

The Java Bridge Implementation

When Flowable encounters a step that requires machine execution (e.g., executing a complex Temporal credit-scoring Saga), a custom Java Delegate triggers the Temporal workflow asynchronously. The Flowable process then enters a native ReceiveTask state, awaiting a system signal.

package com.xenon.banking.bridge;

import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Component;

import com.xenon.banking.temporal.CreditScoringWorkflow;
import com.xenon.banking.temporal.model.ScoringRequest;

@Component("temporalSagaDelegate")
public class TemporalSagaDelegate implements JavaDelegate {

    private final WorkflowClient temporalWorkflowClient;

    public TemporalSagaDelegate(WorkflowClient temporalWorkflowClient) {
        this.temporalWorkflowClient = temporalWorkflowClient;
    }

    @Override
    public void execute(DelegateExecution execution) {
        String applicationId = (String) execution.getVariable("applicationId");
        String executionId = execution.getId();

        // 1. Construct non-blocking options with correlation key
        WorkflowOptions options = WorkflowOptions.newBuilder()
                .setTaskQueue("CREDIT_SCORING_TASK_QUEUE")
                .setWorkflowId("CreditScore-" + applicationId)
                .build();

        // 2. Instantiate Stub
        CreditScoringWorkflow workflowStub = temporalWorkflowClient.newWorkflowStub(CreditScoringWorkflow.class, options);

        // 3. Prepare Input with Flowable Execution Callback Reference
        ScoringRequest request = new ScoringRequest();
        request.setApplicationId(applicationId);
        request.setFlowableExecutionId(executionId);

        // 4. Trigger Temporal Saga Asynchronously
        WorkflowClient.start(workflowStub::executeScoring, request);

        // 5. Flowable context moves to a ReceiveTask node immediately after this execution
    }
}

Enter fullscreen mode Exit fullscreen mode

Completion Callback: Temporal signaling back to Flowable

Upon completion of the Saga, a Temporal Activity posts an asynchronous completion signal back to Flowable's Runtime Service:

package com.xenon.banking.bridge;

import org.flowable.engine.RuntimeService;
import org.springframework.stereotype.Service;

@Service
public class FlowableCallbackService {

    private final RuntimeService flowableRuntimeService;

    public FlowableCallbackService(RuntimeService flowableRuntimeService) {
        this.flowableRuntimeService = flowableRuntimeService;
    }

    public void handleSagaCompletion(String flowableExecutionId, String outcome, double score) {
        // Pass result parameters back to Flowable engine memory context
        flowableRuntimeService.setVariable(flowableExecutionId, "scoreOutcome", outcome);
        flowableRuntimeService.setVariable(flowableExecutionId, "creditScore", score);

        // Trigger Flowable step advancement out of ReceiveTask
        flowableRuntimeService.trigger(flowableExecutionId);
    }
}

Enter fullscreen mode Exit fullscreen mode

Failure Modes, State Recovery, and Transactional Boundaries

In a dual-orchestration topology, edge cases occur primarily at the operational boundary between the two systems. System design must accommodate asymmetric execution states.

Scenario 1: Temporal Saga Fails Completely

If a machine Saga fails and all compensating actions complete successfully, the machine state remains consistent, but the business transaction cannot proceed automatically.

  • Mitigation: The Temporal completion activity signals Flowable with an outcome = 'SYSTEM_ERROR' payload.
  • Flowable Behavior: Flowable evaluates this outcome using a BPMN Exclusive Gateway and routes the application to an operational exception handling queue (Human User Task) for operational staff to investigate or manual retry.

Scenario 2: Human Task Times Out or Is Cancelled

A customer cancels a loan request while the human underwriting task is pending in Flowable, or the review period exceeds defined SLA boundaries.

  • Mitigation: Flowable triggers an Interrupting Boundary Event (Timer or Signal).
  • Temporal Cancellation: Flowable dispatches an explicit RPC request to the Temporal Client API (workflowStub.cancel()). Temporal intercepts the cancellation request, runs any required cleanup activities, and releases allocated system resources (such as active fund holds).

State Synchronization Patterns

To maintain audit integrity, state synchronization across both systems must conform to standard operational principles:

  1. Correlation Keys: Every transaction must carry a global BIAN Correlation ID (correlationId = "BIAN-ORIG-2026-98234"). This identifier must be passed across Flowable executions, Temporal Workflows, Kafka Headers, and downstream microservice trace contexts.
  2. Idempotent Signal Ingestion: Signals sent from Temporal to Flowable must use deterministic execution references (executionId). If network instability causes duplicate delivery of a completion signal, Flowable's execution check rejects processing of redundant payloads.

Observability, Distributed Tracing, and Auditability

Operating dual orchestrators requires unified observability across both machine traces and human audit logs.

[Customer Application] 
       │
       ▼  W3C TraceContext (traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01)
┌──────────────┐
│  Flowable    │ (Generates Human Audit Record: UserTask 'Approved' by User #4092)
└──────┬───────┘
       │ OpenTelemetry Context Propagation (gRPC / Kafka Headers)
       ▼
┌──────────────┐
│  Temporal    │ (Generates Microservice Execution Span: Activity 'DebitLedger' 4ms)
└──────────────┘

Enter fullscreen mode Exit fullscreen mode
  • OpenTelemetry Propagation: Inject the W3C traceparent header into Flowable process variables. When calling Temporal through the gRPC bridge client, populate the OpenTelemetry context. This enables end-to-end tracing in tools like Jaeger or Datadog, spanning from human UI interaction down to database commits.
  • Audit Trail Bifurcation:
  • Regulatory Audit (Compliance): Sourced from Flowable's historical DB tables (ACT_HI_*), providing clear verification of which human approved what action at what time.
  • System Operations Audit (IT): Sourced from Temporal's Event History store, verifying which microservice APIs executed, retry counts, payload hashes, and exact execution timing.

Adopting a dual-orchestration pattern based on Temporal and Flowable provides a structured design for BIAN-compliant banking platforms. By delegating machine-level transactional consistency to Temporal's Saga implementation and long-running organizational processes to Flowable's BPMN engine, core banking systems achieve sub-second technical performance alongside resilient human workflows.

Top comments (0)