Skip to main content
Version: Next

ParallelStart

Category: Common Steps
Namespace: CMS.Plugin.FlowManagement.Abstractions.FlowBusiness.Activitys
Base Class: ParallelStartActivity (SYC.Flow.Kernel)
Module: FlowManagement.Abstractions

Overview​

ParallelStart is a special node used to start parallel flows. When the flow executes to this node, it creates a parallel branch point, allowing multiple flow branches to execute simultaneously. It inherits from SYC.Flow.Kernel.ParallelStartActivity, providing initialization and level code management for parallel flows.

Parallel flows are suitable for scenarios requiring simultaneous execution of multiple independent tasks, such as multiple concurrent checks, parallel processing of multiple workpieces, etc. The ParallelStart node automatically manages level codes for parallel branches, ensuring each branch has a unique identifier.

Business Scenarios​

Applicable Scenarios​

  • Parallel Detection: Simultaneously perform multiple independent quality checks on a product
  • Parallel Processing: Simultaneously process multiple workpieces or batches
  • Parallel Call: Simultaneously call multiple external APIs or services
  • Parallel Printing: Simultaneously print multiple labels or reports
  • Branch Flow: Create multiple parallel executing flow branches based on conditions

Role in System​

ParallelStart plays the role of a parallel flow controller in the LMES flow system:

  • Marks the start point of parallel flow
  • Assigns a unique level code for each parallel branch
  • Creates work item records for parallel flows
  • Manages context information for parallel flows
  • Collaborates with ParallelEnd to achieve complete parallel flow control

Collaboration with Other Nodes​

  • ParallelEnd: Must be paired, ParallelEnd is responsible for converging parallel branches
  • BusinessActivity: Business nodes in parallel branches, execute business logic normally
  • Transition: Multiple transition lines originate from ParallelStart to form parallel branches

Configuration Description​

Basic Configuration​

Property NameTypeRequiredDefaultDescription
ExtendedPropertyBusinessPropertyCollectionNoEmpty CollectionStep extended properties

Configuration Details​

ExtendedProperty​

Description: Extended property collection, allowing custom properties to be added to the node, which can be written to flow context for use by parallel branches.

Value Range: BusinessPropertyCollection object

Notes:

  • Extended properties will be written to flow context when parallel flow starts
  • All parallel branches can access these extended properties
  • Values of extended properties will automatically have "_Value" suffix added as flow context keys

Flow Context​

Input Parameters​

Parameter NameTypeDescription
ApplicationDataobjectApplication data (such as ProcessModel)
Upstream Node DataanyBusiness data written by upstream nodes

Output Parameters​

Parameter NameTypeDescription
ParalleInfoIDictionaryParallel flow info (default System)
LevelCodestringLevel code of current parallel branch
Extended Property ValueanyProperty values configured in ExtendedProperty

Data Flow Description​

  1. Level Code Management: ParallelStart generates a unique level code (LevelCode) for each parallel branch
  2. Context Inheritance: Parallel branches inherit flow context data from before ParallelStart
  3. Data Isolation: Each parallel branch has independent work item (FlowItem), but shares flow context
  4. Key Info Passing: KeyInfo and KeyLabel are passed from current task to parallel branches

Business Logic Description​

Processing Flow​

The execution flow of ParallelStart is as follows:

  1. EnterAsync: Enter parallel flow start node

    • Get current task information (CurrentTask)
    • Create new work item (FlowItem)
    • Set work item properties:
      • StartTime and FinishTime: Current time
      • PartName: Fixed as "System"
      • TaskStat: FlowItemStatus.AutoFinished
      • AutoFinish: 1 (Auto finish flag)
      • EnableCalculate: 1 (Participate in calculation)
      • LevelCode: Current level code
      • KeyInfo and KeyLabel: Inherited from current task
      • TaskName: Node name
    • Add work item to flow instance
    • Update current work item ID
    • Record entry log
  2. Parallel Branch Creation:

    • Flow engine creates multiple parallel branches based on outgoing transitions from ParallelStart
    • Each branch gets a unique level code
  3. ExitAsync: Exit parallel flow start node

    • Calculate execution time
    • Record exit log

Flow Chart​

[Upstream Node]
↓
[ParallelStart]
├─→ [Parallel Branch 1] → [Business Node 1] ┐
├─→ [Parallel Branch 2] → [Business Node 2] ├→ [ParallelEnd]
└─→ [Parallel Branch 3] → [Business Node 3] ┘

Level Code Mechanism​

Level Code (LevelCode) is the core mechanism of parallel flow:

  • Format: Hierarchical structure like "00-1:01-1:02-1:"
  • Function: Uniquely identify each parallel branch and subflow
  • Generation: Generated by ParallelStart based on current task's level code
  • Usage: ParallelEnd uses level code to identify and converge parallel branches

Dependency Services​

Service InterfacePurposeDescription
FlowFlow InstanceAccess flow context and work items
Flow.LoggerLoggerRecord execution logs of parallel flow

Exception Handling​

ParallelStart node itself does not throw business exceptions, but note:

  • Null reference exception if flow instance is null
  • Level code generation failure may affect correct execution of parallel flow
  • Work item addition failure affects flow tracking

Logging​

ParallelStart records the following key logs:

  • Enter Node: Enter, TaskID={taskId}
  • Exit Node: Exit, Time Consumption={milliseconds}ms

Usage Examples​

Basic Example​

{
"Name": "Parallel Detection Flow",
"Activities": [
{
"Type": "BusinessActivity",
"Name": "Prepare Data",
"Alias": "PrepareData"
},
{
"Type": "ParallelStart",
"Name": "Start Parallel Detection",
"Alias": "ParallelStart1"
},
{
"Type": "BusinessActivity",
"Name": "Visual Check",
"Alias": "AppearanceCheck"
},
{
"Type": "BusinessActivity",
"Name": "Dimension Check",
"Alias": "DimensionCheck"
},
{
"Type": "BusinessActivity",
"Name": "Function Check",
"Alias": "FunctionCheck"
},
{
"Type": "ParallelEnd",
"Name": "End Parallel Detection",
"Alias": "ParallelEnd1",
"WaitMode": "WaitAll"
},
{
"Type": "BusinessActivity",
"Name": "Summarize Results",
"Alias": "SummaryResult"
}
],
"Transitions": [
{
"From": "PrepareData",
"To": "ParallelStart1"
},
{
"From": "ParallelStart1",
"To": "AppearanceCheck"
},
{
"From": "ParallelStart1",
"To": "DimensionCheck"
},
{
"From": "ParallelStart1",
"To": "FunctionCheck"
},
{
"From": "AppearanceCheck",
"To": "ParallelEnd1"
},
{
"From": "DimensionCheck",
"To": "ParallelEnd1"
},
{
"From": "FunctionCheck",
"To": "ParallelEnd1"
},
{
"From": "ParallelEnd1",
"To": "SummaryResult"
}
]
}

Advanced Example: With Extended Properties​

{
"Type": "ParallelStart",
"Name": "Start Parallel Print",
"Alias": "ParallelPrintStart",
"ExtendedProperty": [
{
"Name": "PrintCount",
"Value": "3",
"WriteIntoDataItems": true
},
{
"Name": "PrinterGroup",
"Value": "LabelPrinters",
"WriteIntoDataItems": true
}
]
}

Complete Flow Example: Parallel API Call​

{
"Name": "Parallel API Call Flow",
"Activities": [
{
"Type": "BusinessActivity",
"Name": "Get Order Info",
"Alias": "GetOrder"
},
{
"Type": "ParallelStart",
"Name": "Start Parallel Call",
"Alias": "ParallelAPIStart"
},
{
"Type": "ApiCallActivity",
"Name": "Query Inventory",
"Alias": "CheckInventory",
"ApiId": "InventoryAPI"
},
{
"Type": "ApiCallActivity",
"Name": "Query Price",
"Alias": "CheckPrice",
"ApiId": "PriceAPI"
},
{
"Type": "ApiCallActivity",
"Name": "Query Logistics",
"Alias": "CheckLogistics",
"ApiId": "LogisticsAPI"
},
{
"Type": "ParallelEnd",
"Name": "End Parallel Call",
"Alias": "ParallelAPIEnd",
"WaitMode": "WaitAll"
},
{
"Type": "BusinessActivity",
"Name": "Process Results",
"Alias": "ProcessResults"
}
],
"Transitions": [
{
"From": "GetOrder",
"To": "ParallelAPIStart"
},
{
"From": "ParallelAPIStart",
"To": "CheckInventory"
},
{
"From": "ParallelAPIStart",
"To": "CheckPrice"
},
{
"From": "ParallelAPIStart",
"To": "CheckLogistics"
},
{
"From": "CheckInventory",
"To": "ParallelAPIEnd"
},
{
"From": "CheckPrice",
"To": "ParallelAPIEnd"
},
{
"From": "CheckLogistics",
"To": "ParallelAPIEnd"
},
{
"From": "ParallelAPIEnd",
"To": "ProcessResults"
}
]
}

Extension Development Guide​

Inheritance Hierarchy​

Activity (SYC.Flow.Kernel)
└── ParallelStartActivity (SYC.Flow.Kernel)
└── ParallelStart

Overridable Methods​

Method NamePurposeWhen to Override
EnterAsyncExecuted when entering nodeNeed custom parallel flow initialization logic
ExitAsyncExecuted when exiting nodeNeed custom processing after parallel flow start
ParalleInfoParallel flow infoNeed custom parallel branch identification info
LevelCodeLevel codeNeed custom level code generation logic

Custom Parallel Start Node Example​

[Serializable]
[Design("Custom Parallel Start", "Parallel start node with custom logic", Sort = 1)]
[Category("Custom")]
public class CustomParallelStart : ParallelStart
{
[Design("Parallel Branch Count", "Number of parallel branches to create", Sort = 1)]
[Category("Configuration")]
[DataMember]
public int BranchCount { get; set; } = 3;

public override IDictionary ParalleInfo
{
get
{
var info = new SortedList();
for (int i = 0; i < BranchCount; i++)
{
info.Add($"Branch{i + 1}", $"Branch{i + 1}");
}
return info;
}
}

public override async Task EnterAsync(ProcessflowEventArgs e)
{
// Custom initialization logic
Flow.Logger.LogMessage($"Creating {BranchCount} parallel branches", Name);

// Prepare data for each branch
for (int i = 0; i < BranchCount; i++)
{
Flow.DataItems[$"Branch{i}_Data"] = $"Data for Branch{i + 1}";
}

await base.EnterAsync(e);
}
}

Registration and Integration​

  1. Compile Node:

    • Inherit ParallelStart class
    • Add Design and Category attributes
    • Compile to DLL
  2. Deploy Node:

    • Place DLL in LMES plugin directory
    • Restart LMES service
  3. Use Node:

    • Select custom parallel start node in flow designer
    • Configure node properties
    • Connect parallel branches

Notes​

  • ⚠️ Must Pair: ParallelStart must be paired with ParallelEnd, otherwise flow cannot execute correctly
  • ⚠️ Branch Count: Number of parallel branches is determined by number of transition lines outgoing from ParallelStart
  • ⚠️ Level Code: Do not manually modify level code, managed automatically by system
  • ⚠️ Work Item: ParallelStart automatically creates work item with AutoFinished status
  • ⚠️ Data Sharing: All parallel branches share the same flow context, beware of data conflicts
  • ⚠️ Execution Order: Execution order of parallel branches is indeterminate, do not rely on specific order
  • 💡 Best Practices:
    • Prepare data needed by all parallel branches before ParallelStart
    • Use extended properties to pass common configuration to all branches
    • Use different flow context keys for each branch to avoid data overwrite
    • Set appropriate waiting mode (WaitAll or WaitOne) for ParallelEnd

FAQ​

Q1: Must ParallelStart and ParallelEnd be paired?​

A: Yes, they must be paired. ParallelStart marks the start of a parallel flow, ParallelEnd is responsible for converging all parallel branches. If ParallelEnd is missing, the flow cannot end correctly.

Q2: How to control the number of parallel branches?​

A: The number of parallel branches is determined by the number of Transition lines outgoing from ParallelStart. One transition line corresponds to one parallel branch.

Q3: How to share data between parallel branches?​

A: All parallel branches share the same flow context (Flow.DataItems). Data can be passed via flow context, but note:

  • Use different key names to avoid data overwrite
  • Consider using thread-safe data structures
  • Read results of all branches after ParallelEnd

Q4: What is the execution order of parallel branches?​

A: The execution order of parallel branches is indeterminate, decided by the flow engine's scheduling. Do not rely on specific execution order. If sequential execution is needed, use serial flow.

Q5: How to handle exceptions in parallel branches?​

A: Each parallel branch handles exceptions independently. If a branch throws an exception:

  • That branch stops execution
  • Other branches continue execution
  • ParallelEnd's waiting mode determines handling:
    • WaitAll: Wait for all branches to complete (including exception branches)
    • WaitOne: Continue as soon as one branch completes

Update History​

DateVersionDescription
2025-11-281.0Initial Release

Last updated: 2025-11-28