Feature: Scheduler-Tick-Zaehlung korrigieren und Sitzungstotale einfuehren

Der Scheduler-Tab meldete nach erfolgreicher Verarbeitung faelschlich
"keine neuen Dokumente". Ursache war ein hartkodiertes RunSummary.noOp()
im BatchRunTrigger der Bootstrap; der echte Lauf-Summary wurde nie
gelesen.

- Bootstrap: BatchRunProgressObserver erfasst RunSummary aus onRunEnded
  und uebersetzt ihn in den ausgehenden RunSummary fuer das Tick-Ergebnis
- Neuer Wert-Typ SchedulerSessionTotals (success/failed) plus
  Optional-Feld in SchedulerStatus
- DefaultSchedulerControlUseCase setzt die Totale beim start() auf null
  zurueck, summiert pro Started-Tick auf, friert sie beim stop() ein
- GuiSchedulerTab zeigt pro Tick "X verarbeitet, Y Fehler" oder
  "keine neuen Dokumente" sowie ein zusaetzliches Label
  "Seit Scheduler-Start: X verarbeitet, Y Fehler"

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 14:51:36 +02:00
parent ac5b74917f
commit 368cb81b56
6 changed files with 233 additions and 10 deletions
@@ -1094,16 +1094,45 @@ public class BootstrapRunner {
RunLockPort runLockPort = runLockPortFactory.create(
resolveLockFilePath(ctx.startConfiguration()));
BatchRunContext runContext = createRunContext();
java.util.concurrent.atomic.AtomicReference<de.gecheckt.pdf.umbenenner.application.port.in.RunSummary>
capturedSummary = new java.util.concurrent.atomic.AtomicReference<>();
de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProgressObserver capturingObserver =
new de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProgressObserver() {
@Override
public void onRunStarted(RunId runId, int totalCandidates) {
// No GUI feedback for scheduler-driven runs.
}
@Override
public void onDocumentCompleted(
de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionEvent event) {
// No per-document feedback for scheduler-driven runs.
}
@Override
public void onRunEnded(
de.gecheckt.pdf.umbenenner.application.port.in.RunSummary summary) {
capturedSummary.set(summary);
}
};
BatchRunProcessingUseCase useCase = buildProductionBatchUseCase(
ctx.startConfiguration(), runLockPort,
de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProgressObserver.noOp(),
capturingObserver,
de.gecheckt.pdf.umbenenner.application.port.in.BatchRunCancellationToken.neverCancelled());
BatchRunOutcome outcome = useCase.execute(runContext);
runContext.setEndInstant(Instant.now());
if (outcome.isLockUnavailable()) {
return new BatchRunTriggerResult.SkippedBusy();
} else if (outcome.isSuccess()) {
return new BatchRunTriggerResult.Started(Instant.now(), RunSummary.noOp());
de.gecheckt.pdf.umbenenner.application.port.in.RunSummary inSummary =
capturedSummary.get();
RunSummary outSummary = inSummary == null
? RunSummary.noOp()
: new RunSummary(
inSummary.successCount(),
inSummary.failedCount(),
inSummary.skippedCount());
return new BatchRunTriggerResult.Started(Instant.now(), outSummary);
} else {
return new BatchRunTriggerResult.Failed(
"Verarbeitungslauf fehlgeschlagen.",