Skip to Content

Prozess beenden

Der ProcessInstancesClient ermöglicht das manuelle Beenden (Terminieren) von laufenden Prozess-Instanzen.

TerminateProcessInstanceAsync()

Beendet eine laufende Prozess-Instanz:

using ProcessCube.Engine; var engineAddress = "http://localhost:8000"; var client = ClientFactory.CreateProcessInstancesClient(engineAddress); var processInstanceId = "abc-123-def-456"; await client.TerminateProcessInstanceAsync(processInstanceId); Console.WriteLine($"Prozess {processInstanceId} wurde beendet");

Das Terminieren eines Prozesses ist eine destruktive Operation. Der Prozess wird sofort beendet und kann nicht wieder aufgenommen werden (außer durch Retry).

Prozess starten und beenden

using ProcessCube.Engine; var engineAddress = "http://localhost:8000"; var definitionsClient = ClientFactory.CreateProcessDefinitionsClient(engineAddress); var instancesClient = ClientFactory.CreateProcessInstancesClient(engineAddress); // Prozess starten var response = await definitionsClient.StartProcessInstanceAsync( processModelId: "LongRunningProcess", startEventId: "StartEvent_1", initialToken: new { taskId = "TASK-789" } ); var processInstanceId = response.ProcessInstanceId; Console.WriteLine($"Prozess gestartet: {processInstanceId}"); // Warten... await Task.Delay(5000); // Prozess beenden await instancesClient.TerminateProcessInstanceAsync(processInstanceId); Console.WriteLine("Prozess wurde terminiert"); // Status prüfen var instances = await instancesClient.QueryAsync(query => { query.FilterByProcessInstanceId(processInstanceId); }); var instance = instances.SingleOrDefault(); if (instance != null) { Console.WriteLine($"Neuer Status: {instance.State}"); // ProcessState.Terminated }

Mit Validierung

Prüfen Sie vor dem Terminieren, ob der Prozess noch läuft:

using ProcessCube.Engine; var engineAddress = "http://localhost:8000"; var client = ClientFactory.CreateProcessInstancesClient(engineAddress); var processInstanceId = "abc-123"; // 1. Status prüfen var instances = await client.QueryAsync(query => { query.FilterByProcessInstanceId(processInstanceId); }); var instance = instances.SingleOrDefault(); if (instance == null) { Console.WriteLine("Prozess-Instanz nicht gefunden"); return; } // 2. Nur laufende Prozesse beenden if (instance.State == ProcessState.Running || instance.State == ProcessState.Suspended) { await client.TerminateProcessInstanceAsync(processInstanceId); Console.WriteLine($"Prozess {processInstanceId} wurde beendet"); } else { Console.WriteLine($"Prozess ist bereits beendet (Status: {instance.State})"); }

Mehrere Prozesse beenden

using ProcessCube.Engine; var engineAddress = "http://localhost:8000"; var client = ClientFactory.CreateProcessInstancesClient(engineAddress); // Alle laufenden Instanzen eines Prozessmodells finden var instances = await client.QueryAsync(query => { query.FilterByProcessModelId("OrderProcess"); query.FilterByState(ProcessState.Running); }); Console.WriteLine($"Gefunden: {instances.Count} laufende Order-Prozesse"); // Alle beenden foreach (var instance in instances) { try { await client.TerminateProcessInstanceAsync(instance.Id); Console.WriteLine($" ✓ {instance.Id} beendet"); } catch (Exception ex) { Console.WriteLine($" ✗ {instance.Id} Fehler: {ex.Message}"); } }

Beim Beenden mehrerer Prozesse sollten Sie Fehlerbehandlung für jeden einzelnen Prozess implementieren, da einige fehlschlagen könnten.

Prozesse nach Correlation-ID beenden

using ProcessCube.Engine; var engineAddress = "http://localhost:8000"; var client = ClientFactory.CreateProcessInstancesClient(engineAddress); var correlationId = "ORDER-2025-001"; // Alle Prozesse mit dieser Correlation-ID finden var instances = await client.QueryAsync(query => { query.FilterByCorrelationId(correlationId); query.FilterByStates(ProcessState.Running, ProcessState.Suspended); }); Console.WriteLine($"Beende {instances.Count} Prozesse mit Correlation '{correlationId}'"); // Alle zusammenhängenden Prozesse beenden foreach (var instance in instances) { await client.TerminateProcessInstanceAsync(instance.Id); Console.WriteLine($" Beendet: {instance.ProcessModelId} ({instance.Id})"); }

Timeout-basiertes Beenden

Beenden Sie Prozesse, die zu lange laufen:

using ProcessCube.Engine; var engineAddress = "http://localhost:8000"; var client = ClientFactory.CreateProcessInstancesClient(engineAddress); var maxRuntimeHours = 24; // Alle laufenden Prozesse abrufen var instances = await client.QueryAsync(query => { query.FilterByProcessModelId("DataProcessing"); query.FilterByState(ProcessState.Running); }); var now = DateTime.UtcNow; var timeoutInstances = instances .Where(i => (now - i.CreatedAt).TotalHours > maxRuntimeHours) .ToList(); Console.WriteLine($"Gefunden: {timeoutInstances.Count} Prozesse mit Timeout"); foreach (var instance in timeoutInstances) { var runtime = (now - instance.CreatedAt).TotalHours; Console.WriteLine($"Beende Prozess {instance.Id} (Laufzeit: {runtime:F1}h)"); await client.TerminateProcessInstanceAsync(instance.Id); }

Mit Authentifizierung

using ProcessCube.Engine; using ProcessCube.Engine.Client.Identity; // Identity Provider erstellen var identityProvider = new ClientCredentialsIdentityProvider( authorityAddress: "http://localhost:11235", clientId: "admin-service", clientSecret: "secret-key", scope: "engine_write" ); // Token abrufen var identity = await identityProvider.GetIdentityAsync(); // Client mit Identity erstellen var client = ClientFactory.CreateProcessInstancesClient( engineAddress: "http://localhost:8000", identity: identity ); var processInstanceId = "abc-123"; // Prozess beenden (authentifiziert) await client.TerminateProcessInstanceAsync(processInstanceId); Console.WriteLine($"Prozess {processInstanceId} wurde authentifiziert beendet");

Für das Terminieren von Prozessen benötigen Sie den Scope engine_write in Ihrem Access Token.

Beenden mit Logging

using ProcessCube.Engine; using Microsoft.Extensions.Logging; public class ProcessTerminationService { private readonly IProcessInstancesClient _client; private readonly ILogger<ProcessTerminationService> _logger; public ProcessTerminationService( IProcessInstancesClient client, ILogger<ProcessTerminationService> logger) { _client = client; _logger = logger; } public async Task<bool> TerminateProcessAsync( string processInstanceId, string reason) { try { // Status vor Terminierung prüfen var instances = await _client.QueryAsync(query => { query.FilterByProcessInstanceId(processInstanceId); }); var instance = instances.SingleOrDefault(); if (instance == null) { _logger.LogWarning( "Prozess {ProcessInstanceId} nicht gefunden", processInstanceId ); return false; } if (instance.State != ProcessState.Running && instance.State != ProcessState.Suspended) { _logger.LogInformation( "Prozess {ProcessInstanceId} ist bereits beendet (Status: {State})", processInstanceId, instance.State ); return false; } // Terminieren await _client.TerminateProcessInstanceAsync(processInstanceId); _logger.LogInformation( "Prozess {ProcessInstanceId} terminiert. Grund: {Reason}. " + "Model: {ProcessModelId}, Laufzeit: {Runtime}s", processInstanceId, reason, instance.ProcessModelId, (DateTime.UtcNow - instance.CreatedAt).TotalSeconds ); return true; } catch (Exception ex) { _logger.LogError( ex, "Fehler beim Terminieren von Prozess {ProcessInstanceId}", processInstanceId ); return false; } } }

Graceful Shutdown

Implementieren Sie einen kontrollierten Shutdown-Mechanismus:

using ProcessCube.Engine; public class ProcessShutdownManager { private readonly IProcessInstancesClient _client; public ProcessShutdownManager(IProcessInstancesClient client) { _client = client; } public async Task<ShutdownResult> ShutdownProcessAsync( string processInstanceId, int maxWaitSeconds = 30) { var result = new ShutdownResult { ProcessInstanceId = processInstanceId }; try { // 1. Prüfen ob Prozess läuft var instances = await _client.QueryAsync(query => { query.FilterByProcessInstanceId(processInstanceId); }); var instance = instances.SingleOrDefault(); if (instance == null) { result.Success = false; result.Message = "Prozess nicht gefunden"; return result; } if (instance.State != ProcessState.Running) { result.Success = true; result.Message = $"Prozess bereits beendet (Status: {instance.State})"; return result; } // 2. Warten ob Prozess sich selbst beendet var startTime = DateTime.UtcNow; var timeout = TimeSpan.FromSeconds(maxWaitSeconds); while ((DateTime.UtcNow - startTime) < timeout) { await Task.Delay(1000); instances = await _client.QueryAsync(query => { query.FilterByProcessInstanceId(processInstanceId); }); instance = instances.SingleOrDefault(); if (instance?.State == ProcessState.Finished) { result.Success = true; result.Message = "Prozess hat sich selbst beendet"; return result; } } // 3. Timeout erreicht - forciert terminieren await _client.TerminateProcessInstanceAsync(processInstanceId); result.Success = true; result.ForcedTermination = true; result.Message = "Prozess wurde nach Timeout terminiert"; } catch (Exception ex) { result.Success = false; result.Message = $"Fehler: {ex.Message}"; } return result; } } public class ShutdownResult { public string ProcessInstanceId { get; set; } public bool Success { get; set; } public bool ForcedTermination { get; set; } public string Message { get; set; } }

Fehlerbehandlung

using ProcessCube.Engine; using ProcessCube.Engine.Client.Exceptions; var engineAddress = "http://localhost:8000"; var client = ClientFactory.CreateProcessInstancesClient(engineAddress); var processInstanceId = "abc-123"; try { await client.TerminateProcessInstanceAsync(processInstanceId); Console.WriteLine("Prozess erfolgreich beendet"); } catch (EngineClientException ex) when (ex.StatusCode == 404) { Console.WriteLine("Prozess-Instanz nicht gefunden"); } catch (EngineClientException ex) when (ex.StatusCode == 400) { Console.WriteLine("Prozess kann nicht beendet werden"); Console.WriteLine($"Details: {ex.Message}"); } catch (EngineClientException ex) when (ex.StatusCode == 401) { Console.WriteLine("Nicht authentifiziert"); } catch (EngineClientException ex) when (ex.StatusCode == 403) { Console.WriteLine("Fehlende Berechtigung zum Beenden"); } catch (HttpRequestException ex) { Console.WriteLine($"Verbindungsfehler: {ex.Message}"); } catch (Exception ex) { Console.WriteLine($"Unerwarteter Fehler: {ex.Message}"); }

ASP.NET Core API Endpoint

using Microsoft.AspNetCore.Mvc; using ProcessCube.Engine; [ApiController] [Route("api/processes")] public class ProcessManagementController : ControllerBase { private readonly IProcessInstancesClient _client; public ProcessManagementController(IProcessInstancesClient client) { _client = client; } [HttpPost("{processInstanceId}/terminate")] public async Task<IActionResult> TerminateProcess( string processInstanceId, [FromBody] TerminateRequest request) { try { // Status prüfen var instances = await _client.QueryAsync(query => { query.FilterByProcessInstanceId(processInstanceId); }); var instance = instances.SingleOrDefault(); if (instance == null) { return NotFound(new { error = "Prozess nicht gefunden" }); } if (instance.State != ProcessState.Running && instance.State != ProcessState.Suspended) { return BadRequest(new { error = "Prozess kann nicht beendet werden", currentState = instance.State.ToString() }); } // Terminieren await _client.TerminateProcessInstanceAsync(processInstanceId); return Ok(new { message = "Prozess wurde beendet", processInstanceId = processInstanceId, reason = request.Reason }); } catch (Exception ex) { return StatusCode(500, new { error = ex.Message }); } } } public record TerminateRequest(string Reason);

Best Practice: Loggen Sie alle Prozess-Terminierungen mit Grund, Zeitstempel und Benutzer für Audit-Zwecke.

Nächste Schritte