Skip to Content
DocsClientsDotnetProcessesProzess neu starten

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