FlowNode Instances
Der FlowNodeInstancesClient ermöglicht das Abfragen der Ausführungshistorie von BPMN-FlowNodes innerhalb einer Prozess-Instanz.
Was sind FlowNode Instances?
FlowNode Instances repräsentieren die Ausführung einzelner BPMN-Elemente (Tasks, Gateways, Events) in einem Prozess. Sie ermöglichen detaillierte Einblicke in den Prozessverlauf.
Client erstellen
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateFlowNodeInstancesClient(engineAddress);QueryAsync()
Fragt FlowNode Instances mit Filtern ab:
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateFlowNodeInstancesClient(engineAddress);
var processInstanceId = "abc-123-def-456";
// Alle FlowNode Instances einer Prozess-Instanz abrufen
var flowNodes = await client.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
});
Console.WriteLine($"Ausgeführte FlowNodes: {flowNodes.Count}");
foreach (var flowNode in flowNodes)
{
Console.WriteLine($" {flowNode.FlowNodeId}: {flowNode.State}");
Console.WriteLine($" Type: {flowNode.FlowNodeType}");
Console.WriteLine($" Started: {flowNode.CreatedAt:HH:mm:ss}");
if (flowNode.FinishedAt.HasValue)
{
var duration = flowNode.FinishedAt.Value - flowNode.CreatedAt;
Console.WriteLine($" Duration: {duration.TotalSeconds:F2}s");
}
}Filter-Optionen
Nach ProcessInstanceId
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateFlowNodeInstancesClient(engineAddress);
var flowNodes = await client.QueryAsync(query => {
query.FilterByProcessInstanceId("abc-123");
});
Console.WriteLine($"FlowNodes in Prozess: {flowNodes.Count}");Nach FlowNodeId
Alle Ausführungen eines bestimmten FlowNodes:
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateFlowNodeInstancesClient(engineAddress);
// Alle Ausführungen der "CheckInventory" Task
var flowNodes = await client.QueryAsync(query => {
query.FilterByFlowNodeId("Task_CheckInventory");
});
Console.WriteLine($"'CheckInventory' wurde {flowNodes.Count} mal ausgeführt");
// Durchschnittliche Ausführungszeit
var completedNodes = flowNodes.Where(fn => fn.FinishedAt.HasValue);
if (completedNodes.Any())
{
var avgDuration = completedNodes
.Average(fn => (fn.FinishedAt!.Value - fn.CreatedAt).TotalSeconds);
Console.WriteLine($"Durchschnittliche Dauer: {avgDuration:F2}s");
}Nach State
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateFlowNodeInstancesClient(engineAddress);
var processInstanceId = "abc-123";
// Nur laufende FlowNodes
var runningNodes = await client.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
query.FilterByState(FlowNodeState.Running);
});
Console.WriteLine($"Aktuell laufende FlowNodes: {runningNodes.Count}");FlowNodeInstance Properties
| Property | Typ | Beschreibung |
|---|---|---|
Id | string | Eindeutige ID der FlowNode Instance |
FlowNodeId | string | ID des FlowNode aus dem BPMN |
FlowNodeType | FlowNodeType | Art des FlowNode (Task, Gateway, etc.) |
State | FlowNodeState | Aktueller Status |
ProcessInstanceId | string | Zugehörige Prozess-Instanz |
CreatedAt | DateTime | Startzeitpunkt |
FinishedAt | DateTime? | Endzeitpunkt (falls beendet) |
Tokens | Dictionary<TokenType, Token> | Ein/Ausgabe-Tokens |
FlowNodeType Enum
| Type | Beschreibung |
|---|---|
StartEvent | Start-Event |
EndEvent | End-Event |
IntermediateCatchEvent | Intermediate Catch Event |
IntermediateThrowEvent | Intermediate Throw Event |
Task | Standard-Task |
ServiceTask | Service-Task |
UserTask | User-Task |
ManualTask | Manual-Task |
ScriptTask | Script-Task |
CallActivity | Call-Activity |
SubProcess | SubProcess |
ExclusiveGateway | Exclusive Gateway (XOR) |
ParallelGateway | Parallel Gateway (AND) |
InclusiveGateway | Inclusive Gateway (OR) |
EventBasedGateway | Event-Based Gateway |
FlowNodeState Enum
| State | Beschreibung |
|---|---|
Running | FlowNode wird ausgeführt |
Suspended | FlowNode wartet (z.B. User Task) |
Finished | FlowNode erfolgreich beendet |
Error | FlowNode mit Fehler beendet |
Terminated | FlowNode wurde abgebrochen |
Prozess-Pfad nachvollziehen
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateFlowNodeInstancesClient(engineAddress);
var processInstanceId = "abc-123";
// FlowNodes chronologisch sortiert abrufen
var flowNodes = await client.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
});
var orderedFlowNodes = flowNodes
.OrderBy(fn => fn.CreatedAt)
.ToList();
Console.WriteLine("Prozess-Pfad:");
foreach (var flowNode in orderedFlowNodes)
{
var status = flowNode.State == FlowNodeState.Finished ? "✓" : "⟳";
var duration = flowNode.FinishedAt.HasValue
? $"({(flowNode.FinishedAt.Value - flowNode.CreatedAt).TotalSeconds:F1}s)"
: "(läuft)";
Console.WriteLine($"{status} {flowNode.FlowNodeId} {duration}");
}Die zeitliche Reihenfolge der FlowNode Instances zeigt den tatsächlichen Ausführungspfad durch das BPMN-Diagramm.
Token-Daten auslesen
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateFlowNodeInstancesClient(engineAddress);
var processInstanceId = "abc-123";
var flowNodes = await client.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
query.FilterByFlowNodeId("Task_ProcessOrder");
});
var flowNode = flowNodes.FirstOrDefault();
if (flowNode != null && flowNode.Tokens.ContainsKey(TokenType.OnEnter))
{
var onEnterToken = flowNode.Tokens[TokenType.OnEnter];
// Token-Payload deserialisieren
var payload = onEnterToken.GetPayload<OrderData>();
Console.WriteLine($"Order-ID: {payload.OrderId}");
Console.WriteLine($"Amount: {payload.Amount}");
}
internal sealed record OrderData(string OrderId, decimal Amount);Performance-Analyse
using ProcessCube.Engine;
public class ProcessPerformanceAnalyzer
{
private readonly IFlowNodeInstancesClient _client;
public ProcessPerformanceAnalyzer(IFlowNodeInstancesClient client)
{
_client = client;
}
public async Task<PerformanceReport> AnalyzeProcessAsync(string processInstanceId)
{
var flowNodes = await _client.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
});
var report = new PerformanceReport
{
ProcessInstanceId = processInstanceId,
TotalFlowNodes = flowNodes.Count
};
// Prozess-Start und -Ende
var startNode = flowNodes
.Where(fn => fn.FlowNodeType == FlowNodeType.StartEvent)
.OrderBy(fn => fn.CreatedAt)
.FirstOrDefault();
var endNode = flowNodes
.Where(fn => fn.FlowNodeType == FlowNodeType.EndEvent && fn.FinishedAt.HasValue)
.OrderByDescending(fn => fn.FinishedAt)
.FirstOrDefault();
if (startNode != null && endNode != null && endNode.FinishedAt.HasValue)
{
report.TotalDuration = endNode.FinishedAt.Value - startNode.CreatedAt;
}
// Längste Task finden
var completedTasks = flowNodes
.Where(fn => fn.FlowNodeType == FlowNodeType.Task ||
fn.FlowNodeType == FlowNodeType.ServiceTask ||
fn.FlowNodeType == FlowNodeType.UserTask)
.Where(fn => fn.FinishedAt.HasValue)
.Select(fn => new
{
fn.FlowNodeId,
Duration = fn.FinishedAt!.Value - fn.CreatedAt
})
.OrderByDescending(t => t.Duration)
.ToList();
if (completedTasks.Any())
{
var longestTask = completedTasks.First();
report.LongestTaskId = longestTask.FlowNodeId;
report.LongestTaskDuration = longestTask.Duration;
}
return report;
}
}
public class PerformanceReport
{
public string ProcessInstanceId { get; set; }
public int TotalFlowNodes { get; set; }
public TimeSpan TotalDuration { get; set; }
public string? LongestTaskId { get; set; }
public TimeSpan LongestTaskDuration { get; set; }
}Mit Authentifizierung
using ProcessCube.Engine;
using ProcessCube.Engine.Client.Identity;
var identityProvider = new ClientCredentialsIdentityProvider(
authorityAddress: "http://localhost:11235",
clientId: "monitoring-service",
clientSecret: "secret-key",
scope: "engine_read"
);
var identity = await identityProvider.GetIdentityAsync();
var client = ClientFactory.CreateFlowNodeInstancesClient(
engineAddress: "http://localhost:8000",
identity: identity
);
var flowNodes = await client.QueryAsync(query => {
query.FilterByProcessInstanceId("abc-123");
});
Console.WriteLine($"FlowNodes: {flowNodes.Count}");Fehlerbehandlung
using ProcessCube.Engine;
using ProcessCube.Engine.Client.Exceptions;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateFlowNodeInstancesClient(engineAddress);
try
{
var flowNodes = await client.QueryAsync(query => {
query.FilterByProcessInstanceId("abc-123");
});
Console.WriteLine($"Gefunden: {flowNodes.Count} FlowNodes");
}
catch (EngineClientException ex) when (ex.StatusCode == 404)
{
Console.WriteLine("Prozess-Instanz nicht gefunden");
}
catch (EngineClientException ex) when (ex.StatusCode == 401)
{
Console.WriteLine("Nicht authentifiziert");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Verbindungsfehler: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Fehler: {ex.Message}");
}Verwendungszweck: FlowNode Instances eignen sich hervorragend für Prozess-Monitoring, Performance-Analyse und Debugging von Prozessausführungen.
Nächste Schritte
- Prozess-Instanzen abfragen - Prozess-Status prüfen
- User Tasks - User Task FlowNodes bearbeiten
- Prozess-Verwaltung - Zurück zur Übersicht