diff options
3 files changed, 51 insertions, 41 deletions
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/monitoring/ConnectionCheckService.kt b/src/main/kotlin/dev/dnpm/etl/processor/monitoring/ConnectionCheckService.kt index 81ad922..b76a99f 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/monitoring/ConnectionCheckService.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/monitoring/ConnectionCheckService.kt @@ -26,22 +26,18 @@ import jakarta.annotation.PostConstruct import org.apache.kafka.clients.consumer.Consumer import org.apache.kafka.common.errors.TimeoutException import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.http.RequestEntity +import org.springframework.http.* import org.springframework.scheduling.annotation.Scheduled import org.springframework.web.client.RestTemplate import org.springframework.web.util.UriComponentsBuilder import reactor.core.publisher.Sinks +import java.time.Instant import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration interface ConnectionCheckService { - fun connectionAvailable(): Boolean + fun connectionAvailable(): ConnectionCheckResult } @@ -51,9 +47,11 @@ sealed class ConnectionCheckResult { abstract val available: Boolean - data class KafkaConnectionCheckResult(override val available: Boolean) : ConnectionCheckResult() - data class RestConnectionCheckResult(override val available: Boolean) : ConnectionCheckResult() - data class GPasConnectionCheckResult(override val available: Boolean) : ConnectionCheckResult() + abstract val timestamp: Instant + + data class KafkaConnectionCheckResult(override val available: Boolean, override val timestamp: Instant) : ConnectionCheckResult() + data class RestConnectionCheckResult(override val available: Boolean, override val timestamp: Instant) : ConnectionCheckResult() + data class GPasConnectionCheckResult(override val available: Boolean, override val timestamp: Instant) : ConnectionCheckResult() } class KafkaConnectionCheckService( @@ -62,25 +60,26 @@ class KafkaConnectionCheckService( private val connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult> ) : OutputConnectionCheckService { - private var connectionAvailable: Boolean = false + private var result = ConnectionCheckResult.KafkaConnectionCheckResult(false, Instant.now()) @PostConstruct @Scheduled(cron = "0 * * * * *") fun check() { - connectionAvailable = try { - null != consumer.listTopics(5.seconds.toJavaDuration()) + result = try { + val available = null != consumer.listTopics(5.seconds.toJavaDuration()) + ConnectionCheckResult.KafkaConnectionCheckResult(available, Instant.now()) } catch (e: TimeoutException) { - false + ConnectionCheckResult.KafkaConnectionCheckResult(false, Instant.now()) } connectionCheckUpdateProducer.emitNext( - ConnectionCheckResult.KafkaConnectionCheckResult(connectionAvailable), + result, Sinks.EmitFailureHandler.FAIL_FAST ) } - override fun connectionAvailable(): Boolean { - return this.connectionAvailable + override fun connectionAvailable(): ConnectionCheckResult.KafkaConnectionCheckResult { + return this.result } } @@ -92,27 +91,29 @@ class RestConnectionCheckService( private val connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult> ) : OutputConnectionCheckService { - private var connectionAvailable: Boolean = false + private var result: ConnectionCheckResult.RestConnectionCheckResult = ConnectionCheckResult.RestConnectionCheckResult(false, Instant.now()) @PostConstruct @Scheduled(cron = "0 * * * * *") fun check() { - connectionAvailable = try { - restTemplate.getForEntity( + result = try { + val available = restTemplate.getForEntity( restTargetProperties.uri?.replace("/etl/api", "").toString(), String::class.java ).statusCode == HttpStatus.OK + + ConnectionCheckResult.RestConnectionCheckResult(available, Instant.now()) } catch (e: Exception) { - false + ConnectionCheckResult.RestConnectionCheckResult(false, Instant.now()) } connectionCheckUpdateProducer.emitNext( - ConnectionCheckResult.RestConnectionCheckResult(connectionAvailable), + result, Sinks.EmitFailureHandler.FAIL_FAST ) } - override fun connectionAvailable(): Boolean { - return this.connectionAvailable + override fun connectionAvailable(): ConnectionCheckResult.RestConnectionCheckResult { + return this.result } } @@ -123,12 +124,12 @@ class GPasConnectionCheckService( private val connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult> ) : ConnectionCheckService { - private var connectionAvailable: Boolean = false + private var result: ConnectionCheckResult.GPasConnectionCheckResult = ConnectionCheckResult.GPasConnectionCheckResult(false, Instant.now()) @PostConstruct @Scheduled(cron = "0 * * * * *") fun check() { - connectionAvailable = try { + result = try { val uri = UriComponentsBuilder.fromUriString( gPasConfigProperties.uri?.replace("/\$pseudonymizeAllowCreate", "/\$pseudonymize").toString() ) @@ -141,22 +142,25 @@ class GPasConnectionCheckService( if (!gPasConfigProperties.username.isNullOrBlank() && !gPasConfigProperties.password.isNullOrBlank()) { headers.setBasicAuth(gPasConfigProperties.username, gPasConfigProperties.password) } - restTemplate.exchange( + + val available = restTemplate.exchange( uri, HttpMethod.GET, HttpEntity<Void>(headers), Void::class.java ).statusCode == HttpStatus.OK + + ConnectionCheckResult.GPasConnectionCheckResult(available, Instant.now()) } catch (e: Exception) { - false + ConnectionCheckResult.GPasConnectionCheckResult(false, Instant.now()) } connectionCheckUpdateProducer.emitNext( - ConnectionCheckResult.GPasConnectionCheckResult(connectionAvailable), + result, Sinks.EmitFailureHandler.FAIL_FAST ) } - override fun connectionAvailable(): Boolean { - return this.connectionAvailable + override fun connectionAvailable(): ConnectionCheckResult.GPasConnectionCheckResult { + return this.result } }
\ No newline at end of file diff --git a/src/main/resources/templates/configs/gPasConnectionAvailable.html b/src/main/resources/templates/configs/gPasConnectionAvailable.html index 6dccc60..ea9dead 100644 --- a/src/main/resources/templates/configs/gPasConnectionAvailable.html +++ b/src/main/resources/templates/configs/gPasConnectionAvailable.html @@ -2,15 +2,18 @@ <h2><span>🟦</span> gPAS nicht konfiguriert - Patienten-IDs werden intern anonymisiert</h2> </th:block> <th:block th:if="${gPasConnectionAvailable != null}"> - <h2><span th:if="${gPasConnectionAvailable}">✅</span><span th:if="${not(gPasConnectionAvailable)}">⚡</span> Verbindung zu gPAS</h2> + <h2><span th:if="${gPasConnectionAvailable.available}">✅</span><span th:if="${not(gPasConnectionAvailable.available)}">⚡</span> Verbindung zu gPAS</h2> <div> - Die Verbindung ist aktuell - <strong th:if="${gPasConnectionAvailable}" style="color: green">verfügbar.</strong> - <strong th:if="${not(gPasConnectionAvailable)}" style="color: red">nicht verfügbar.</strong> + Stand: <time style="font-weight: bold" th:datetime="${#temporals.formatISO(gPasConnectionAvailable.timestamp)}" th:text="${#temporals.formatISO(gPasConnectionAvailable.timestamp)}"></time> + </div> + <div> + <span>Die Verbindung ist aktuell</span> + <strong th:if="${gPasConnectionAvailable.available}" style="color: green">verfügbar.</strong> + <strong th:if="${not(gPasConnectionAvailable.available)}" style="color: red">nicht verfügbar.</strong> </div> <div class="connection-display border"> <img th:src="@{/server.png}" alt="ETL-Processor" /> - <span class="connection" th:classappend="${gPasConnectionAvailable ? 'available' : ''}"></span> + <span class="connection" th:classappend="${gPasConnectionAvailable.available ? 'available' : ''}"></span> <img th:src="@{/server.png}" alt="gPAS" /> <span>ETL-Processor</span> <span></span> diff --git a/src/main/resources/templates/configs/outputConnectionAvailable.html b/src/main/resources/templates/configs/outputConnectionAvailable.html index 2b18b75..63d77db 100644 --- a/src/main/resources/templates/configs/outputConnectionAvailable.html +++ b/src/main/resources/templates/configs/outputConnectionAvailable.html @@ -1,12 +1,15 @@ -<h2><span th:if="${outputConnectionAvailable}">✅</span><span th:if="${not(outputConnectionAvailable)}">⚡</span> MTB-File Verbindung</h2> +<h2><span th:if="${outputConnectionAvailable.available}">✅</span><span th:if="${not(outputConnectionAvailable.available)}">⚡</span> MTB-File Verbindung</h2> <div> - Verbindung über <code>[[ ${mtbFileSender} ]]</code>. Die Verbindung ist aktuell - <strong th:if="${outputConnectionAvailable}" style="color: green">verfügbar.</strong> - <strong th:if="${not(outputConnectionAvailable)}" style="color: red">nicht verfügbar.</strong> + Stand: <time style="font-weight: bold" th:datetime="${#temporals.formatISO(outputConnectionAvailable.timestamp)}" th:text="${#temporals.formatISO(outputConnectionAvailable.timestamp)}"></time> +</div> +<div> + Verbindung über <code>[[ ${mtbFileSender} ]]</code>. Die Verbindung ist aktuell. + <strong th:if="${outputConnectionAvailable.available}" style="color: green">verfügbar.</strong> + <strong th:if="${not(outputConnectionAvailable.available)}" style="color: red">nicht verfügbar.</strong> </div> <div class="connection-display border"> <img th:src="@{/server.png}" alt="ETL-Processor" /> - <span class="connection" th:classappend="${outputConnectionAvailable ? 'available' : ''}"></span> + <span class="connection" th:classappend="${outputConnectionAvailable.available ? 'available' : ''}"></span> <img th:if="${mtbFileSender.startsWith('Rest')}" th:src="@{/server.png}" alt="bwHC-Backend" /> <img th:if="${mtbFileSender.startsWith('Kafka')}" th:src="@{/kafka.png}" alt="Kafka-Broker" /> <span>ETL-Processor</span> |
