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
- Prozess neu starten - Terminierte Prozesse wiederholen
- Prozess-Instanzen abfragen - Status überwachen
- Prozess-Verwaltung - Zurück zur Übersicht