feat(zns-import): Healthchecks optimiert und Konsul-Discovery erweitert

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-16 14:57:30 +02:00
parent f3d5651ab7
commit 29c35c524b
5 changed files with 41 additions and 24 deletions
@@ -19,10 +19,10 @@ import java.util.zip.ZipInputStream
* Domänenobjekte über die jeweiligen Repositories (Upsert-Logik).
*
* Die Verarbeitungsreihenfolge ist fix:
* 1. VEREIN01.DAT → Verein (via VereinRepository)
* 2. LIZENZ01.DAT → Reiter (via ReiterRepository)
* 3. PFERDE01.DAT → Pferd (via HorseRepository)
* 4. RICHT01.DAT → Funktionaer (via FunktionaerRepository)
* 1. VEREIN01.DAT → Verein (via VereinRepository)
* 2. LIZENZ01.DAT → Reiter (via ReiterRepository)
* 3. PFERDE01.DAT → Pferd (via HorseRepository)
* 4. RICHT01.DAT → Funktionär (via FunktionaerRepository)
*
* Dieser Service hat **keine** Spring-Abhängigkeit und kann daher sowohl
* im Backend (REST-Upload) als auch in der Compose Desktop App (Offline-Import)
@@ -55,6 +55,7 @@ class ZnsImportService(
/**
* Extrahiert die relevanten Dateien aus dem ZIP-Archiv.
* Optimiert: Nutzt BufferedReader für zeilenweises Einlesen, ohne das gesamte File in den RAM zu laden.
*/
fun extrahiereDateien(zipInputStream: InputStream): Map<String, List<String>> {
val dateien = mutableMapOf<String, List<String>>()
@@ -65,24 +66,25 @@ class ZnsImportService(
val fileName = entry.name.uppercase().substringAfterLast("/")
if (fileName in setOf(FILE_VEREIN, FILE_LIZENZ, FILE_PFERDE, FILE_RICHT)) {
val outputStream = java.io.ByteArrayOutputStream()
val buffer = ByteArray(4096)
var len: Int
while (zip.read(buffer).also { len = it } > 0) {
outputStream.write(buffer, 0, len)
// Wir lesen den Stream direkt zeilenweise mit dem korrekten Encoding
val reader = zip.bufferedReader(CP850)
val lines = mutableListOf<String>()
// WICHTIG: Wir dürfen den Reader NICHT schließen (use), da sonst der ZipInputStream geschlossen wird!
var line = reader.readLine()
while (line != null) {
if (line.isNotBlank()) {
lines.add(line)
}
line = reader.readLine()
}
val content = outputStream.toString(CP850)
val lines = content.split(Regex("\\r?\\n|\\r")).filter { it.isNotBlank() }
dateien[fileName] = lines
}
zip.closeEntry()
entry = zip.nextEntry
}
} finally {
// Wir schließen den ZipInputStream NICHT mit use,
// um den zugrunde liegenden zipInputStream nicht vorzeitig zu schließen.
// Falls der Aufrufer den Stream schließen will, soll er das tun.
// Aber wir müssen sicherstellen, dass wir alle Entries gelesen haben.
// Wir schließen den ZipInputStream NICHT hier, sondern überlassen es dem Aufrufer
}
return dateien
}
+2 -2
View File
@@ -92,8 +92,8 @@ USER ${APP_USER}
EXPOSE 8095 5005
HEALTHCHECK --interval=15s --timeout=3s --start-period=40s --retries=3 \
CMD curl -fsS --max-time 2 http://localhost:8095/actuator/health/readiness || exit 1
HEALTHCHECK --interval=15s --timeout=5s --start-period=60s --retries=5 \
CMD curl -fsS --max-time 5 http://localhost:${SERVER_PORT:-8095}/actuator/health/readiness || exit 1
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75.0 \
-XX:+UseG1GC \
@@ -28,9 +28,12 @@ spring:
discovery:
enabled: ${CONSUL_ENABLED:true}
register: ${CONSUL_ENABLED:true}
prefer-ip-address: ${SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS:true}
service-name: ${spring.application.name}
health-check-path: /actuator/health
health-check-interval: 10s
instance-id: ${spring.application.name}-${server.port}-${random.uuid}
health-check-interval: 15s
instance-id: ${spring.application.name}:${server.port}:${random.uuid}
hostname: ${SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME:localhost}
management:
endpoints:
web:
@@ -39,6 +42,8 @@ management:
endpoint:
health:
show-details: always
probes:
enabled: true
app:
service-name: ${spring.application.name}