Prozess neu starten
Der ProcessInstancesClient ermöglicht das Neustarten (Retry) von beendeten oder fehlerhaften Prozess-Instanzen.
RetryProcessInstanceAsync()
Startet eine terminierte oder fehlerhafte Prozess-Instanz neu:
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateProcessInstancesClient(engineAddress);
var processInstanceId = "abc-123-def-456";
await client.RetryProcessInstanceAsync(processInstanceId);
Console.WriteLine($"Prozess {processInstanceId} wurde neu gestartet");Retry startet den Prozess von vorne und verwendet die ursprünglichen Input-Daten. Alle bisherigen Ausführungszustände werden zurückgesetzt.
Fehlerhafte Prozesse neu starten
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateProcessInstancesClient(engineAddress);
// Alle fehlerhaften Prozesse eines Modells finden
var instances = await client.QueryAsync(query => {
query.FilterByProcessModelId("OrderProcess");
query.FilterByState(ProcessState.Error);
});
Console.WriteLine($"Gefunden: {instances.Count} fehlerhafte Order-Prozesse");
foreach (var instance in instances)
{
try
{
await client.RetryProcessInstanceAsync(instance.Id);
Console.WriteLine($" ✓ {instance.Id} neu gestartet");
}
catch (Exception ex)
{
Console.WriteLine($" ✗ {instance.Id} Fehler: {ex.Message}");
}
}Terminierte Prozesse neu starten
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 nicht gefunden");
return;
}
Console.WriteLine($"Aktueller Status: {instance.State}");
// 2. Nur terminierte oder fehlerhafte Prozesse neu starten
if (instance.State == ProcessState.Terminated || instance.State == ProcessState.Error)
{
await client.RetryProcessInstanceAsync(processInstanceId);
Console.WriteLine("Prozess wurde neu gestartet");
// 3. Neuen Status prüfen
await Task.Delay(1000);
instances = await client.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
});
instance = instances.SingleOrDefault();
Console.WriteLine($"Neuer Status: {instance?.State}");
}
else
{
Console.WriteLine($"Prozess kann nicht neu gestartet werden (Status: {instance.State})");
}Vollständiges Beispiel: Terminate und Retry
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var definitionsClient = ClientFactory.CreateProcessDefinitionsClient(engineAddress);
var instancesClient = ClientFactory.CreateProcessInstancesClient(engineAddress);
// 1. Prozess starten
var response = await definitionsClient.StartProcessInstanceAsync(
processModelId: "DataProcessing",
startEventId: "StartEvent_1",
initialToken: new { dataId = "DATA-789", action = "process" }
);
var processInstanceId = response.ProcessInstanceId;
Console.WriteLine($"1. Prozess gestartet: {processInstanceId}");
// 2. Warten
await Task.Delay(2000);
// 3. Terminieren
await instancesClient.TerminateProcessInstanceAsync(processInstanceId);
Console.WriteLine("2. Prozess terminiert");
// 4. Status nach Terminierung prüfen
var instances = await instancesClient.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
});
var instance = instances.Single();
Console.WriteLine($" Status: {instance.State}"); // ProcessState.Terminated
// 5. Neu starten
await instancesClient.RetryProcessInstanceAsync(processInstanceId);
Console.WriteLine("3. Prozess neu gestartet");
// 6. Warten auf Abschluss
await Task.Delay(3000);
// 7. Finaler Status
instances = await instancesClient.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
});
instance = instances.Single();
Console.WriteLine($" Finaler Status: {instance.State}");Beim Retry wird der Prozess mit den ursprünglichen Input-Daten gestartet. Wenn die Ursache des Fehlers in den Daten liegt, wird der Prozess erneut fehlschlagen.
Retry mit Wartezeit
Warten Sie zwischen Terminierung und Retry:
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateProcessInstancesClient(engineAddress);
var processInstanceId = "abc-123";
// Terminieren
await client.TerminateProcessInstanceAsync(processInstanceId);
Console.WriteLine("Prozess terminiert");
// Wartezeit (z.B. für externe Systeme)
await Task.Delay(TimeSpan.FromSeconds(10));
// Retry
await client.RetryProcessInstanceAsync(processInstanceId);
Console.WriteLine("Prozess nach 10 Sekunden neu gestartet");Automatisches Retry bei Fehlern
using ProcessCube.Engine;
public class ProcessRetryService
{
private readonly IProcessInstancesClient _client;
public ProcessRetryService(IProcessInstancesClient client)
{
_client = client;
}
public async Task<RetryResult> AutoRetryAsync(
string processInstanceId,
int maxRetries = 3,
int delaySeconds = 5)
{
var result = new RetryResult
{
ProcessInstanceId = processInstanceId,
MaxRetries = maxRetries
};
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
Console.WriteLine($"Retry-Versuch {attempt}/{maxRetries}...");
// Retry ausführen
await _client.RetryProcessInstanceAsync(processInstanceId);
// Warten bis Prozess beendet ist
var success = await WaitForCompletionAsync(
processInstanceId,
TimeSpan.FromSeconds(30)
);
if (success)
{
result.Success = true;
result.SuccessfulAttempt = attempt;
Console.WriteLine($"✓ Erfolgreich nach {attempt} Versuchen");
break;
}
// Wartezeit vor nächstem Versuch
if (attempt < maxRetries)
{
await Task.Delay(TimeSpan.FromSeconds(delaySeconds));
}
}
catch (Exception ex)
{
result.Errors.Add($"Attempt {attempt}: {ex.Message}");
Console.WriteLine($"✗ Versuch {attempt} fehlgeschlagen: {ex.Message}");
}
}
if (!result.Success)
{
result.Message = $"Alle {maxRetries} Retry-Versuche fehlgeschlagen";
}
return result;
}
private async Task<bool> WaitForCompletionAsync(
string processInstanceId,
TimeSpan timeout)
{
var startTime = DateTime.UtcNow;
while ((DateTime.UtcNow - startTime) < timeout)
{
await Task.Delay(1000);
var instances = await _client.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
});
var instance = instances.SingleOrDefault();
if (instance == null)
return false;
if (instance.State == ProcessState.Finished)
return true;
if (instance.State == ProcessState.Error ||
instance.State == ProcessState.Terminated)
return false;
}
return false;
}
}
public class RetryResult
{
public string ProcessInstanceId { get; set; }
public bool Success { get; set; }
public int MaxRetries { get; set; }
public int SuccessfulAttempt { get; set; }
public string Message { get; set; }
public List<string> Errors { get; set; } = new();
}Batch-Retry
Mehrere Prozesse gleichzeitig neu starten:
using ProcessCube.Engine;
var engineAddress = "http://localhost:8000";
var client = ClientFactory.CreateProcessInstancesClient(engineAddress);
// Alle fehlerhaften Prozesse finden
var errorInstances = await client.QueryAsync(query => {
query.FilterByProcessModelId("OrderProcess");
query.FilterByState(ProcessState.Error);
});
Console.WriteLine($"Starte {errorInstances.Count} fehlerhafte Prozesse neu...");
var results = new List<(string Id, bool Success, string Error)>();
// Parallel neu starten
var retryTasks = errorInstances.Select(async instance =>
{
try
{
await client.RetryProcessInstanceAsync(instance.Id);
return (instance.Id, true, string.Empty);
}
catch (Exception ex)
{
return (instance.Id, false, ex.Message);
}
});
results.AddRange(await Task.WhenAll(retryTasks));
// Ergebnis ausgeben
var successCount = results.Count(r => r.Success);
var failCount = results.Count(r => !r.Success);
Console.WriteLine($"\nErgebnis:");
Console.WriteLine($" Erfolgreich: {successCount}");
Console.WriteLine($" Fehlgeschlagen: {failCount}");
if (failCount > 0)
{
Console.WriteLine("\nFehler:");
foreach (var (id, _, error) in results.Where(r => !r.Success))
{
Console.WriteLine($" {id}: {error}");
}
}Mit Authentifizierung
using ProcessCube.Engine;
using ProcessCube.Engine.Client.Identity;
// Identity Provider erstellen
var identityProvider = new ClientCredentialsIdentityProvider(
authorityAddress: "http://localhost:11235",
clientId: "retry-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 neu starten (authentifiziert)
await client.RetryProcessInstanceAsync(processInstanceId);
Console.WriteLine($"Prozess {processInstanceId} wurde authentifiziert neu gestartet");Für Retry-Operationen benötigen Sie den Scope engine_write in Ihrem Access Token.
Überwachung nach Retry
using ProcessCube.Engine;
public class RetryMonitorService
{
private readonly IProcessInstancesClient _client;
public RetryMonitorService(IProcessInstancesClient client)
{
_client = client;
}
public async Task<MonitorResult> RetryAndMonitorAsync(
string processInstanceId,
TimeSpan monitorDuration)
{
var result = new MonitorResult { ProcessInstanceId = processInstanceId };
try
{
// Retry ausführen
await _client.RetryProcessInstanceAsync(processInstanceId);
result.RetryTimestamp = DateTime.UtcNow;
Console.WriteLine($"Prozess neu gestartet, überwache für {monitorDuration.TotalSeconds}s");
// Überwachen
var endTime = DateTime.UtcNow.Add(monitorDuration);
while (DateTime.UtcNow < endTime)
{
await Task.Delay(2000);
var instances = await _client.QueryAsync(query => {
query.FilterByProcessInstanceId(processInstanceId);
});
var instance = instances.SingleOrDefault();
if (instance == null)
{
result.Success = false;
result.Message = "Prozess nicht mehr gefunden";
break;
}
result.CurrentState = instance.State;
Console.WriteLine($" Status: {instance.State}");
if (instance.State == ProcessState.Finished)
{
result.Success = true;
result.Message = "Prozess erfolgreich abgeschlossen";
result.CompletionTimestamp = DateTime.UtcNow;
result.Duration = result.CompletionTimestamp - result.RetryTimestamp;
break;
}
else if (instance.State == ProcessState.Error)
{
result.Success = false;
result.Message = "Prozess erneut fehlgeschlagen";
break;
}
}
if (!result.Success && result.CurrentState == ProcessState.Running)
{
result.Message = "Überwachungszeitraum abgelaufen, Prozess läuft noch";
}
}
catch (Exception ex)
{
result.Success = false;
result.Message = $"Fehler: {ex.Message}";
}
return result;
}
}
public class MonitorResult
{
public string ProcessInstanceId { get; set; }
public bool Success { get; set; }
public ProcessState CurrentState { get; set; }
public string Message { get; set; }
public DateTime RetryTimestamp { get; set; }
public DateTime CompletionTimestamp { get; set; }
public TimeSpan Duration { 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.RetryProcessInstanceAsync(processInstanceId);
Console.WriteLine("Prozess erfolgreich neu gestartet");
}
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 neu gestartet 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 für Retry");
}
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 ProcessRetryController : ControllerBase
{
private readonly IProcessInstancesClient _client;
public ProcessRetryController(IProcessInstancesClient client)
{
_client = client;
}
[HttpPost("{processInstanceId}/retry")]
public async Task<IActionResult> RetryProcess(string processInstanceId)
{
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.Error &&
instance.State != ProcessState.Terminated)
{
return BadRequest(new
{
error = "Prozess kann nicht neu gestartet werden",
currentState = instance.State.ToString(),
message = "Nur fehlerhafte oder terminierte Prozesse können neu gestartet werden"
});
}
// Retry ausführen
await _client.RetryProcessInstanceAsync(processInstanceId);
return Ok(new
{
message = "Prozess wurde neu gestartet",
processInstanceId = processInstanceId,
previousState = instance.State.ToString()
});
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
}Best Practice: Loggen Sie alle Retry-Operationen mit Zeitstempel, ursprünglichem Status und Benutzer für Audit- und Debugging-Zwecke.
Nächste Schritte
- Prozess-Instanzen abfragen - Status nach Retry prüfen
- Prozess beenden - Prozesse abbrechen
- Prozess-Verwaltung - Zurück zur Übersicht