V2.8 Fix: „Erneut verarbeiten" setzt DB-Status vor Mini-Lauf zurück
Das Problem: Der „Erneut verarbeiten"-Button startete einen Mini-Lauf, ohne den DB-Status der selektierten Dateien zurückzusetzen. Dateien mit FAILED_FINAL-Status wurden daher vom Use Case übersprungen. Die Lösung: 1. Neue Methode startReprocessing() in GuiBatchRunCoordinator, die resetPort.reset() SYNCHRON vor dem Mini-Lauf aufruft. 2. handleReprocessSelected() in GuiBatchRunTab nutzt jetzt startReprocessing() statt startMiniRun() direkt. 3. Test-Fix: noOpReset muss die Fingerprints in der erfolgreich-zurückgesetzt- Liste enthalten, damit successCount() > 0 ist. Spec-Konformität: - Reset erfolgt synchron vor dem Worker-Thread-Start - Keine neue Architektur-Verletzung - Hexagonale Architektur bleibt sauber (Port/Adapter) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
+2
-3
@@ -43,6 +43,8 @@ import de.gecheckt.pdf.umbenenner.application.validation.editor.EditorValidation
|
||||
import de.gecheckt.pdf.umbenenner.application.validation.editor.EditorValidationSeverity;
|
||||
import de.gecheckt.pdf.umbenenner.application.validation.technicaltest.CorrectionExecutionService;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
@@ -51,8 +53,6 @@ import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.Label;
|
||||
@@ -70,7 +70,6 @@ import javafx.scene.input.ClipboardContent;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
||||
+42
@@ -268,6 +268,48 @@ public final class GuiBatchRunCoordinator {
|
||||
return startWorker(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a reprocessing operation: resets the database status of the specified
|
||||
* fingerprints and immediately launches a targeted mini-run for them.
|
||||
* <p>
|
||||
* This method is the preferred entry point for "Erneut verarbeiten" (reprocess)
|
||||
* actions in the GUI. It ensures that documents marked as FAILED_FINAL or otherwise
|
||||
* ineligible for processing are reset before the mini-run begins, so they are
|
||||
* reprocessed rather than skipped.
|
||||
* <p>
|
||||
* The reset executes synchronously on the caller's thread before the worker thread
|
||||
* is started. This guarantees that the mini-run sees the documents in a
|
||||
* reprocessable state.
|
||||
*
|
||||
* @param configFilePath the configuration file; must not be {@code null}
|
||||
* @param fingerprintFilter the set of document fingerprints to reset and process;
|
||||
* must not be {@code null}
|
||||
* @return {@code true} when a new worker thread was started, {@code false} when a run
|
||||
* was already in progress or when the reset failed for all fingerprints
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
*/
|
||||
public boolean startReprocessing(Path configFilePath,
|
||||
Set<DocumentFingerprint> fingerprintFilter) {
|
||||
Objects.requireNonNull(configFilePath, "configFilePath must not be null");
|
||||
Objects.requireNonNull(fingerprintFilter, "fingerprintFilter must not be null");
|
||||
if (isRunning()) {
|
||||
return false;
|
||||
}
|
||||
// Reset the database status synchronously before starting the mini-run.
|
||||
// This ensures that documents are not skipped due to FAILED_FINAL or other
|
||||
// terminal states.
|
||||
ResetDocumentStatusResult resetResult = resetPort.reset(configFilePath, fingerprintFilter);
|
||||
if (resetResult.successCount() == 0) {
|
||||
LOG.warn("GUI-Reprocessing: Reset für alle {} Dokumente fehlgeschlagen; "
|
||||
+ "Mini-Lauf wird nicht gestartet.", fingerprintFilter.size());
|
||||
return false;
|
||||
}
|
||||
LOG.info("GUI-Reprocessing: {} von {} Dokumenten erfolgreich zurückgesetzt.",
|
||||
resetResult.successCount(), resetResult.requestedCount());
|
||||
// Now start the mini-run with the reset fingerprints.
|
||||
return startMiniRun(configFilePath, fingerprintFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a reset-only operation for the supplied fingerprint set.
|
||||
* <p>
|
||||
|
||||
+4
-2
@@ -4,7 +4,6 @@ import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -707,7 +706,10 @@ public final class GuiBatchRunTab {
|
||||
// Mark selected rows as reset-pending immediately for visual feedback.
|
||||
markSelectedRowsAsResetPending();
|
||||
|
||||
boolean started = coordinator.startMiniRun(configPath, snapshot);
|
||||
// Reset database status and start mini-run. The reset executes synchronously
|
||||
// before the mini-run worker thread is started, ensuring documents are not
|
||||
// skipped due to FAILED_FINAL status.
|
||||
boolean started = coordinator.startReprocessing(configPath, snapshot);
|
||||
if (!started) {
|
||||
showMessage(ALREADY_RUNNING_HINT);
|
||||
return;
|
||||
|
||||
-2
@@ -18,8 +18,6 @@ import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunCancellationToken;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProgressObserver;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionEvent;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionStatus;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.ResetDocumentStatusResult;
|
||||
|
||||
+4
-1
@@ -196,7 +196,10 @@ class GuiBatchRunTabSelectionSmokeTest {
|
||||
GuiBatchRunLauncher noOpLauncher = (p, o, t) ->
|
||||
GuiBatchRunLaunchOutcome.rejected("not used");
|
||||
GuiResetDocumentStatusPort noOpReset = (p, fps) ->
|
||||
new ResetDocumentStatusResult(fps.size(), Set.of(), Map.of());
|
||||
// Return a successful reset for all fingerprints. The reset doesn't actually
|
||||
// change anything in this test, but successCount() returns successfullyReset.size(),
|
||||
// so we must return the fingerprints in the successfully reset set.
|
||||
new ResetDocumentStatusResult(fps.size(), fps, Map.of());
|
||||
|
||||
CountDownLatch tabReady = new CountDownLatch(1);
|
||||
AtomicReferenceCapture<GuiBatchRunTab> tabRef = new AtomicReferenceCapture<>();
|
||||
|
||||
-1
@@ -2,7 +2,6 @@ package de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
+1
@@ -6,6 +6,7 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.ClockPort;
|
||||
import de.gecheckt.pdf.umbenenner.application.service.AiResponseValidator.AiValidationResult;
|
||||
import de.gecheckt.pdf.umbenenner.domain.model.AiErrorClassification;
|
||||
import de.gecheckt.pdf.umbenenner.domain.model.DateSource;
|
||||
import de.gecheckt.pdf.umbenenner.domain.model.NamingProposal;
|
||||
|
||||
+1
@@ -7,6 +7,7 @@ import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProgressObserver;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionEvent;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionStatus;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentKnownProcessable;
|
||||
|
||||
-4
@@ -12,14 +12,10 @@ import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunCancellationToken;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunOutcome;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProcessingUseCase;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProgressObserver;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionEvent;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionStatus;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.RunSummary;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.FingerprintPort;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.FingerprintResult;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.FingerprintSuccess;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.FingerprintTechnicalError;
|
||||
import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.PdfTextExtractionPort;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingLogger;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.RunLockPort;
|
||||
|
||||
-4
@@ -2,14 +2,11 @@ package de.gecheckt.pdf.umbenenner.application.usecase;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
@@ -17,7 +14,6 @@ import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
-1
@@ -6,7 +6,6 @@ import static org.assertj.core.api.Assertions.assertThatNullPointerException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
+1
-3
@@ -24,8 +24,6 @@ import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiConfigurationLoadException;
|
||||
import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiStartupContext;
|
||||
import de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun.GuiBatchRunLaunchOutcome;
|
||||
import de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun.GuiBatchRunLauncher;
|
||||
import de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun.GuiMiniRunLauncher;
|
||||
import de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun.GuiResetDocumentStatusPort;
|
||||
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationEditorState;
|
||||
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationEditorStateFactory;
|
||||
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationFileSnapshot;
|
||||
@@ -56,7 +54,6 @@ import de.gecheckt.pdf.umbenenner.application.config.startup.StartConfiguration;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunOutcome;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProcessingUseCase;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.in.ResetDocumentStatusResult;
|
||||
import de.gecheckt.pdf.umbenenner.application.usecase.DefaultResetDocumentStatusUseCase;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.AiContentSensitivity;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.AiInvocationPort;
|
||||
import de.gecheckt.pdf.umbenenner.application.port.out.ClockPort;
|
||||
@@ -77,6 +74,7 @@ import de.gecheckt.pdf.umbenenner.application.service.AiNamingService;
|
||||
import de.gecheckt.pdf.umbenenner.application.service.AiResponseValidator;
|
||||
import de.gecheckt.pdf.umbenenner.application.service.DocumentProcessingCoordinator;
|
||||
import de.gecheckt.pdf.umbenenner.application.usecase.DefaultBatchRunProcessingUseCase;
|
||||
import de.gecheckt.pdf.umbenenner.application.usecase.DefaultResetDocumentStatusUseCase;
|
||||
import de.gecheckt.pdf.umbenenner.application.validation.editor.EditorConfigurationValidator;
|
||||
import de.gecheckt.pdf.umbenenner.application.validation.technicaltest.ProviderTechnicalTestService;
|
||||
import de.gecheckt.pdf.umbenenner.application.validation.technicaltest.TechnicalTestOrchestrator;
|
||||
|
||||
Reference in New Issue
Block a user