Fix V2.8: selectedRows-Leerproblem und isRunning()-Inkonsistenz behoben
- markSelectedRowsAsResetPending() schützt selectedRows jetzt mit selectionSyncInProgress=true, sodass der TableView-SelectionModel- Listener die Selektion nicht löscht, wenn Zeilen ersetzt werden - isRunning() und updateButtonStates() verwenden runningProperty.get() statt coordinator.isRunning() für konsistentes Verhalten zwischen Button-Zustand und Selektion - Diagnose-LOG am Anfang von handleReprocessSelected() gibt isRunning() und selectedRows.size() aus (Laufend=false, Selektion>0 erwartet) - Alle [TEMP-TRACE]-Logs entfernt aus GuiBatchRunCoordinator, SqliteUnitOfWorkAdapter, SqliteDocumentRecordRepositoryAdapter und DocumentProcessingCoordinator Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
+4
-6
@@ -298,13 +298,11 @@ public final class GuiBatchRunCoordinator {
|
|||||||
// Reset the database status synchronously before starting the mini-run.
|
// Reset the database status synchronously before starting the mini-run.
|
||||||
// This ensures that documents are not skipped due to FAILED_FINAL or other
|
// This ensures that documents are not skipped due to FAILED_FINAL or other
|
||||||
// terminal states.
|
// terminal states.
|
||||||
LOG.info("[TEMP-TRACE] startReprocessing: Konfiguration={}, Fingerprints={}",
|
LOG.info("GUI-Erneut-Verarbeiten: Starte Status-Reset für {} Dokument(e), Konfiguration={}.",
|
||||||
configFilePath, fingerprintFilter.stream()
|
fingerprintFilter.size(), configFilePath);
|
||||||
.map(f -> f.sha256Hex().substring(0, 8) + "…")
|
|
||||||
.collect(java.util.stream.Collectors.joining(", ")));
|
|
||||||
ResetDocumentStatusResult resetResult = resetPort.reset(configFilePath, fingerprintFilter);
|
ResetDocumentStatusResult resetResult = resetPort.reset(configFilePath, fingerprintFilter);
|
||||||
LOG.info("[TEMP-TRACE] startReprocessing: Reset-Ergebnis: {} erfolgreich, {} fehlgeschlagen; Fehler={}",
|
LOG.info("GUI-Erneut-Verarbeiten: Status-Reset abgeschlossen – {} erfolgreich, {} fehlgeschlagen.",
|
||||||
resetResult.successCount(), resetResult.failureCount(), resetResult.failures());
|
resetResult.successCount(), resetResult.failureCount());
|
||||||
if (resetResult.successCount() == 0) {
|
if (resetResult.successCount() == 0) {
|
||||||
LOG.warn("GUI-Reprocessing: Reset für alle {} Dokumente fehlgeschlagen; "
|
LOG.warn("GUI-Reprocessing: Reset für alle {} Dokumente fehlgeschlagen; "
|
||||||
+ "Mini-Lauf wird nicht gestartet.", fingerprintFilter.size());
|
+ "Mini-Lauf wird nicht gestartet.", fingerprintFilter.size());
|
||||||
|
|||||||
+11
-4
@@ -285,7 +285,7 @@ public final class GuiBatchRunTab {
|
|||||||
* @return {@code true} while the coordinator is processing a run
|
* @return {@code true} while the coordinator is processing a run
|
||||||
*/
|
*/
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return coordinator.isRunning();
|
return runningProperty.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -687,6 +687,8 @@ public final class GuiBatchRunTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleReprocessSelected() {
|
private void handleReprocessSelected() {
|
||||||
|
LOG.info("GUI-Erneut-Verarbeiten: handleReprocessSelected aufgerufen. "
|
||||||
|
+ "Laufend={}, Selektion={}.", isRunning(), selectedRows.size());
|
||||||
if (isRunning() || selectedRows.isEmpty()) {
|
if (isRunning() || selectedRows.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -766,8 +768,13 @@ public final class GuiBatchRunTab {
|
|||||||
*/
|
*/
|
||||||
private void markSelectedRowsAsResetPending() {
|
private void markSelectedRowsAsResetPending() {
|
||||||
List<GuiBatchRunResultRow> toMark = new ArrayList<>(selectedRows);
|
List<GuiBatchRunResultRow> toMark = new ArrayList<>(selectedRows);
|
||||||
for (GuiBatchRunResultRow row : toMark) {
|
selectionSyncInProgress = true;
|
||||||
upsertResultRowByFingerprint(GuiBatchRunResultRow.resetMarker(row));
|
try {
|
||||||
|
for (GuiBatchRunResultRow row : toMark) {
|
||||||
|
upsertResultRowByFingerprint(GuiBatchRunResultRow.resetMarker(row));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
selectionSyncInProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -822,7 +829,7 @@ public final class GuiBatchRunTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateButtonStates() {
|
private void updateButtonStates() {
|
||||||
boolean running = coordinator.isRunning();
|
boolean running = runningProperty.get();
|
||||||
startButton.setDisable(running);
|
startButton.setDisable(running);
|
||||||
if (!running) {
|
if (!running) {
|
||||||
cancelButton.setDisable(true);
|
cancelButton.setDisable(true);
|
||||||
|
|||||||
+1
-8
@@ -108,13 +108,8 @@ public class SqliteDocumentRecordRepositoryAdapter implements DocumentRecordRepo
|
|||||||
SKIPPED_ALREADY_PROCESSED, SKIPPED_FINAL_FAILURE ->
|
SKIPPED_ALREADY_PROCESSED, SKIPPED_FINAL_FAILURE ->
|
||||||
new DocumentKnownProcessable(record);
|
new DocumentKnownProcessable(record);
|
||||||
};
|
};
|
||||||
logger.info("[TEMP-TRACE] findByFingerprint: fingerprint={}, jdbcUrl={}, Ergebnis={}",
|
|
||||||
fingerprint.sha256Hex(), jdbcUrl, result.getClass().getSimpleName());
|
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
// Document not found
|
|
||||||
logger.info("[TEMP-TRACE] findByFingerprint: fingerprint={}, jdbcUrl={}, Ergebnis=DocumentUnknown",
|
|
||||||
fingerprint.sha256Hex(), jdbcUrl);
|
|
||||||
return new DocumentUnknown();
|
return new DocumentUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,9 +316,7 @@ public class SqliteDocumentRecordRepositoryAdapter implements DocumentRecordRepo
|
|||||||
PreparedStatement statement = connection.prepareStatement(sql)) {
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
|
||||||
statement.setString(1, fingerprint.sha256Hex());
|
statement.setString(1, fingerprint.sha256Hex());
|
||||||
int rowsAffected = statement.executeUpdate();
|
statement.executeUpdate();
|
||||||
logger.info("[TEMP-TRACE] deleteByFingerprint: fingerprint={}, jdbcUrl={}, rowsAffected={}",
|
|
||||||
fingerprint.sha256Hex(), jdbcUrl, rowsAffected);
|
|
||||||
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
String message = "Failed to delete document record for fingerprint '"
|
String message = "Failed to delete document record for fingerprint '"
|
||||||
|
|||||||
-4
@@ -178,8 +178,6 @@ public class SqliteUnitOfWorkAdapter implements UnitOfWorkPort {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void resetDocumentByFingerprint(DocumentFingerprint fingerprint) {
|
public void resetDocumentByFingerprint(DocumentFingerprint fingerprint) {
|
||||||
logger.info("[TEMP-TRACE] resetDocumentByFingerprint: Fingerprint={}, jdbcUrl={}",
|
|
||||||
fingerprint.sha256Hex(), jdbcUrl);
|
|
||||||
// Delete attempts first (FK constraint: processing_attempt → document_record)
|
// Delete attempts first (FK constraint: processing_attempt → document_record)
|
||||||
SqliteProcessingAttemptRepositoryAdapter attemptRepo =
|
SqliteProcessingAttemptRepositoryAdapter attemptRepo =
|
||||||
new SqliteProcessingAttemptRepositoryAdapter(jdbcUrl) {
|
new SqliteProcessingAttemptRepositoryAdapter(jdbcUrl) {
|
||||||
@@ -199,8 +197,6 @@ public class SqliteUnitOfWorkAdapter implements UnitOfWorkPort {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
recordRepo.deleteByFingerprint(fingerprint);
|
recordRepo.deleteByFingerprint(fingerprint);
|
||||||
logger.info("[TEMP-TRACE] resetDocumentByFingerprint: Löschung abgeschlossen für Fingerprint={}",
|
|
||||||
fingerprint.sha256Hex());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-3
@@ -351,9 +351,6 @@ public class DocumentProcessingCoordinator {
|
|||||||
// Step 1: Load the document master record
|
// Step 1: Load the document master record
|
||||||
DocumentRecordLookupResult lookupResult =
|
DocumentRecordLookupResult lookupResult =
|
||||||
documentRecordRepository.findByFingerprint(fingerprint);
|
documentRecordRepository.findByFingerprint(fingerprint);
|
||||||
logger.info("[TEMP-TRACE] processDeferredOutcome: Fingerprint={}, Lookup-Ergebnis={}",
|
|
||||||
fingerprint.sha256Hex(), lookupResult.getClass().getSimpleName());
|
|
||||||
|
|
||||||
// Step 2: Handle persistence lookup failure
|
// Step 2: Handle persistence lookup failure
|
||||||
if (lookupResult instanceof PersistenceLookupTechnicalFailure failure) {
|
if (lookupResult instanceof PersistenceLookupTechnicalFailure failure) {
|
||||||
logger.error("Cannot process '{}': master record lookup failed: {}",
|
logger.error("Cannot process '{}': master record lookup failed: {}",
|
||||||
|
|||||||
Reference in New Issue
Block a user