Diagnoselogs und Test für DB-Reset-Verifikation (FAILED_FINAL)
- [TEMP-TRACE] INFO-Logs in SqliteDocumentRecordRepositoryAdapter: deleteByFingerprint() zeigt Fingerprint, jdbcUrl und rowsAffected; findByFingerprint() zeigt Fingerprint, jdbcUrl und Lookup-Ergebnis - [TEMP-TRACE] Log in DocumentProcessingCoordinator.processDeferredOutcome() zeigt Fingerprint und Lookup-Ergebnis-Typ nach DB-Abfrage - Bestehende [TEMP-TRACE] Logs in GuiBatchRunCoordinator und SqliteUnitOfWorkAdapter sind ebenfalls enthalten - Neuer Test resetDocumentByFingerprint_deletesFailedFinalRecord_resultIsDocumentUnknown: legt FAILED_FINAL-Datensatz in echter SQLite-DB an, führt Reset aus und prüft, dass der Datensatz danach DocumentUnknown zurückliefert Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
+6
@@ -298,7 +298,13 @@ 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={}",
|
||||||
|
configFilePath, fingerprintFilter.stream()
|
||||||
|
.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={}",
|
||||||
|
resetResult.successCount(), resetResult.failureCount(), resetResult.failures());
|
||||||
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());
|
||||||
|
|||||||
+8
-4
@@ -101,16 +101,20 @@ public class SqliteDocumentRecordRepositoryAdapter implements DocumentRecordRepo
|
|||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
// Document exists - map to appropriate result type based on status
|
// Document exists - map to appropriate result type based on status
|
||||||
DocumentRecord record = mapResultSetToDocumentRecord(rs, fingerprint);
|
DocumentRecord record = mapResultSetToDocumentRecord(rs, fingerprint);
|
||||||
|
DocumentRecordLookupResult result = switch (record.overallStatus()) {
|
||||||
return switch (record.overallStatus()) {
|
|
||||||
case SUCCESS -> new DocumentTerminalSuccess(record);
|
case SUCCESS -> new DocumentTerminalSuccess(record);
|
||||||
case FAILED_FINAL -> new DocumentTerminalFinalFailure(record);
|
case FAILED_FINAL -> new DocumentTerminalFinalFailure(record);
|
||||||
case READY_FOR_AI, PROPOSAL_READY, PROCESSING, FAILED_RETRYABLE,
|
case READY_FOR_AI, PROPOSAL_READY, PROCESSING, FAILED_RETRYABLE,
|
||||||
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;
|
||||||
} else {
|
} else {
|
||||||
// Document not found
|
// Document not found
|
||||||
|
logger.info("[TEMP-TRACE] findByFingerprint: fingerprint={}, jdbcUrl={}, Ergebnis=DocumentUnknown",
|
||||||
|
fingerprint.sha256Hex(), jdbcUrl);
|
||||||
return new DocumentUnknown();
|
return new DocumentUnknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,8 +322,8 @@ public class SqliteDocumentRecordRepositoryAdapter implements DocumentRecordRepo
|
|||||||
|
|
||||||
statement.setString(1, fingerprint.sha256Hex());
|
statement.setString(1, fingerprint.sha256Hex());
|
||||||
int rowsAffected = statement.executeUpdate();
|
int rowsAffected = statement.executeUpdate();
|
||||||
logger.debug("Deleted {} document_record row(s) for fingerprint: {}",
|
logger.info("[TEMP-TRACE] deleteByFingerprint: fingerprint={}, jdbcUrl={}, rowsAffected={}",
|
||||||
rowsAffected, fingerprint.sha256Hex());
|
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,6 +178,8 @@ 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) {
|
||||||
@@ -197,6 +199,8 @@ public class SqliteUnitOfWorkAdapter implements UnitOfWorkPort {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
recordRepo.deleteByFingerprint(fingerprint);
|
recordRepo.deleteByFingerprint(fingerprint);
|
||||||
|
logger.info("[TEMP-TRACE] resetDocumentByFingerprint: Löschung abgeschlossen für Fingerprint={}",
|
||||||
|
fingerprint.sha256Hex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+42
@@ -16,6 +16,7 @@ import org.junit.jupiter.api.io.TempDir;
|
|||||||
|
|
||||||
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentPersistenceException;
|
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentPersistenceException;
|
||||||
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecord;
|
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecord;
|
||||||
|
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentTerminalFinalFailure;
|
||||||
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentUnknown;
|
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentUnknown;
|
||||||
import de.gecheckt.pdf.umbenenner.application.port.out.FailureCounters;
|
import de.gecheckt.pdf.umbenenner.application.port.out.FailureCounters;
|
||||||
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingAttempt;
|
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingAttempt;
|
||||||
@@ -295,4 +296,45 @@ class SqliteUnitOfWorkAdapterTest {
|
|||||||
assertThat(docRepository.findByFingerprint(fingerprint)).isInstanceOf(DocumentUnknown.class);
|
assertThat(docRepository.findByFingerprint(fingerprint)).isInstanceOf(DocumentUnknown.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stellt sicher, dass ein Dokument mit Status FAILED_FINAL nach dem Reset nicht mehr
|
||||||
|
* auffindbar ist. Dieser Test deckt den Reprocessing-Pfad ab, bei dem der GUI-Nutzer
|
||||||
|
* ein final fehlgeschlagenes Dokument erneut verarbeiten lässt.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void resetDocumentByFingerprint_deletesFailedFinalRecord_resultIsDocumentUnknown() {
|
||||||
|
DocumentFingerprint fingerprint = new DocumentFingerprint(
|
||||||
|
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
|
||||||
|
Instant now = Instant.now().truncatedTo(ChronoUnit.MICROS);
|
||||||
|
DocumentRecord record = new DocumentRecord(
|
||||||
|
fingerprint,
|
||||||
|
new SourceDocumentLocator("/source/failed-final.pdf"),
|
||||||
|
"failed-final.pdf",
|
||||||
|
ProcessingStatus.FAILED_FINAL,
|
||||||
|
new FailureCounters(2, 0),
|
||||||
|
now.minusSeconds(10),
|
||||||
|
null,
|
||||||
|
now.minusSeconds(20),
|
||||||
|
now,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
SqliteDocumentRecordRepositoryAdapter docRepository =
|
||||||
|
new SqliteDocumentRecordRepositoryAdapter(jdbcUrl);
|
||||||
|
|
||||||
|
// Datensatz mit FAILED_FINAL anlegen
|
||||||
|
unitOfWorkAdapter.executeInTransaction(txOps -> txOps.createDocumentRecord(record));
|
||||||
|
assertThat(docRepository.findByFingerprint(fingerprint))
|
||||||
|
.isInstanceOf(DocumentTerminalFinalFailure.class);
|
||||||
|
|
||||||
|
// Reset ausführen
|
||||||
|
unitOfWorkAdapter.executeInTransaction(txOps ->
|
||||||
|
txOps.resetDocumentByFingerprint(fingerprint));
|
||||||
|
|
||||||
|
// Nach dem Reset muss der Datensatz vollständig entfernt sein
|
||||||
|
assertThat(docRepository.findByFingerprint(fingerprint))
|
||||||
|
.isInstanceOf(DocumentUnknown.class);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -351,6 +351,8 @@ 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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user