mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-04-20 17:56:50 +00:00
feat: push connection available state to client
This commit is contained in:
parent
fa89a64ddd
commit
531a8589db
@ -94,11 +94,6 @@ class AppConfiguration {
|
|||||||
return ReportService(objectMapper)
|
return ReportService(objectMapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
fun statisticsUpdateProducer(): Sinks.Many<Any> {
|
|
||||||
return Sinks.many().multicast().directBestEffort()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun transformationService(
|
fun transformationService(
|
||||||
objectMapper: ObjectMapper,
|
objectMapper: ObjectMapper,
|
||||||
@ -119,5 +114,15 @@ class AppConfiguration {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun statisticsUpdateProducer(): Sinks.Many<Any> {
|
||||||
|
return Sinks.many().multicast().directBestEffort()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun configsUpdateProducer(): Sinks.Many<Boolean> {
|
||||||
|
return Sinks.many().multicast().directBestEffort()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ import org.springframework.kafka.core.KafkaTemplate
|
|||||||
import org.springframework.kafka.listener.ContainerProperties
|
import org.springframework.kafka.listener.ContainerProperties
|
||||||
import org.springframework.kafka.listener.KafkaMessageListenerContainer
|
import org.springframework.kafka.listener.KafkaMessageListenerContainer
|
||||||
import org.springframework.retry.support.RetryTemplate
|
import org.springframework.retry.support.RetryTemplate
|
||||||
|
import reactor.core.publisher.Sinks
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(
|
@EnableConfigurationProperties(
|
||||||
@ -81,8 +82,8 @@ class AppKafkaConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun connectionCheckService(consumerFactory: ConsumerFactory<String, String>): ConnectionCheckService {
|
fun connectionCheckService(consumerFactory: ConsumerFactory<String, String>, configsUpdateProducer: Sinks.Many<Boolean>): ConnectionCheckService {
|
||||||
return KafkaConnectionCheckService(consumerFactory.createConsumer())
|
return KafkaConnectionCheckService(consumerFactory.createConsumer(), configsUpdateProducer)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -32,6 +32,7 @@ import org.springframework.context.annotation.Configuration
|
|||||||
import org.springframework.core.annotation.Order
|
import org.springframework.core.annotation.Order
|
||||||
import org.springframework.retry.support.RetryTemplate
|
import org.springframework.retry.support.RetryTemplate
|
||||||
import org.springframework.web.client.RestTemplate
|
import org.springframework.web.client.RestTemplate
|
||||||
|
import reactor.core.publisher.Sinks
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(
|
@EnableConfigurationProperties(
|
||||||
@ -64,9 +65,10 @@ class AppRestConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
fun connectionCheckService(
|
fun connectionCheckService(
|
||||||
restTemplate: RestTemplate,
|
restTemplate: RestTemplate,
|
||||||
restTargetProperties: RestTargetProperties
|
restTargetProperties: RestTargetProperties,
|
||||||
|
configsUpdateProducer: Sinks.Many<Boolean>
|
||||||
): ConnectionCheckService {
|
): ConnectionCheckService {
|
||||||
return RestConnectionCheckService(restTemplate, restTargetProperties)
|
return RestConnectionCheckService(restTemplate, restTargetProperties, configsUpdateProducer)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,11 @@ import dev.dnpm.etl.processor.config.RestTargetProperties
|
|||||||
import jakarta.annotation.PostConstruct
|
import jakarta.annotation.PostConstruct
|
||||||
import org.apache.kafka.clients.consumer.Consumer
|
import org.apache.kafka.clients.consumer.Consumer
|
||||||
import org.apache.kafka.common.errors.TimeoutException
|
import org.apache.kafka.common.errors.TimeoutException
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.scheduling.annotation.Scheduled
|
import org.springframework.scheduling.annotation.Scheduled
|
||||||
import org.springframework.web.client.RestTemplate
|
import org.springframework.web.client.RestTemplate
|
||||||
|
import reactor.core.publisher.Sinks
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
import kotlin.time.toJavaDuration
|
import kotlin.time.toJavaDuration
|
||||||
|
|
||||||
@ -37,7 +39,9 @@ interface ConnectionCheckService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class KafkaConnectionCheckService(
|
class KafkaConnectionCheckService(
|
||||||
private val consumer: Consumer<String, String>
|
private val consumer: Consumer<String, String>,
|
||||||
|
@Qualifier("configsUpdateProducer")
|
||||||
|
private val configsUpdateProducer: Sinks.Many<Boolean>
|
||||||
) : ConnectionCheckService {
|
) : ConnectionCheckService {
|
||||||
|
|
||||||
private var connectionAvailable: Boolean = false
|
private var connectionAvailable: Boolean = false
|
||||||
@ -51,6 +55,7 @@ class KafkaConnectionCheckService(
|
|||||||
} catch (e: TimeoutException) {
|
} catch (e: TimeoutException) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
configsUpdateProducer.emitNext(connectionAvailable, Sinks.EmitFailureHandler.FAIL_FAST)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun connectionAvailable(): Boolean {
|
override fun connectionAvailable(): Boolean {
|
||||||
@ -61,7 +66,9 @@ class KafkaConnectionCheckService(
|
|||||||
|
|
||||||
class RestConnectionCheckService(
|
class RestConnectionCheckService(
|
||||||
private val restTemplate: RestTemplate,
|
private val restTemplate: RestTemplate,
|
||||||
private val restTargetProperties: RestTargetProperties
|
private val restTargetProperties: RestTargetProperties,
|
||||||
|
@Qualifier("configsUpdateProducer")
|
||||||
|
private val configsUpdateProducer: Sinks.Many<Boolean>
|
||||||
) : ConnectionCheckService {
|
) : ConnectionCheckService {
|
||||||
|
|
||||||
private var connectionAvailable: Boolean = false
|
private var connectionAvailable: Boolean = false
|
||||||
@ -77,6 +84,7 @@ class RestConnectionCheckService(
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
configsUpdateProducer.emitNext(connectionAvailable, Sinks.EmitFailureHandler.FAIL_FAST)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun connectionAvailable(): Boolean {
|
override fun connectionAvailable(): Boolean {
|
||||||
|
@ -23,14 +23,21 @@ import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
|||||||
import dev.dnpm.etl.processor.output.MtbFileSender
|
import dev.dnpm.etl.processor.output.MtbFileSender
|
||||||
import dev.dnpm.etl.processor.pseudonym.Generator
|
import dev.dnpm.etl.processor.pseudonym.Generator
|
||||||
import dev.dnpm.etl.processor.services.TransformationService
|
import dev.dnpm.etl.processor.services.TransformationService
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.http.codec.ServerSentEvent
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
import org.springframework.ui.Model
|
import org.springframework.ui.Model
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import reactor.core.publisher.Flux
|
||||||
|
import reactor.core.publisher.Sinks
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(path = ["configs"])
|
@RequestMapping(path = ["configs"])
|
||||||
class ConfigController(
|
class ConfigController(
|
||||||
|
@Qualifier("configsUpdateProducer")
|
||||||
|
private val configsUpdateProducer: Sinks.Many<Boolean>,
|
||||||
private val transformationService: TransformationService,
|
private val transformationService: TransformationService,
|
||||||
private val pseudonymGenerator: Generator,
|
private val pseudonymGenerator: Generator,
|
||||||
private val mtbFileSender: MtbFileSender,
|
private val mtbFileSender: MtbFileSender,
|
||||||
@ -58,4 +65,13 @@ class ConfigController(
|
|||||||
return "configs/connectionAvailable"
|
return "configs/connectionAvailable"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping(path = ["events"], produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
|
||||||
|
fun events(): Flux<ServerSentEvent<Any>> {
|
||||||
|
return configsUpdateProducer.asFlux().map {
|
||||||
|
ServerSentEvent.builder<Any>()
|
||||||
|
.event("connection-available").id("none").data("")
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -22,6 +22,7 @@ package dev.dnpm.etl.processor.web
|
|||||||
import dev.dnpm.etl.processor.monitoring.RequestRepository
|
import dev.dnpm.etl.processor.monitoring.RequestRepository
|
||||||
import dev.dnpm.etl.processor.monitoring.RequestStatus
|
import dev.dnpm.etl.processor.monitoring.RequestStatus
|
||||||
import dev.dnpm.etl.processor.monitoring.RequestType
|
import dev.dnpm.etl.processor.monitoring.RequestType
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.http.codec.ServerSentEvent
|
import org.springframework.http.codec.ServerSentEvent
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
@ -38,6 +39,7 @@ import java.time.temporal.ChronoUnit
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(path = ["/statistics"])
|
@RequestMapping(path = ["/statistics"])
|
||||||
class StatisticsRestController(
|
class StatisticsRestController(
|
||||||
|
@Qualifier("statisticsUpdateProducer")
|
||||||
private val statisticsUpdateProducer: Sinks.Many<Any>,
|
private val statisticsUpdateProducer: Sinks.Many<Any>,
|
||||||
private val requestRepository: RequestRepository
|
private val requestRepository: RequestRepository
|
||||||
) {
|
) {
|
||||||
|
@ -37,7 +37,10 @@
|
|||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section th:insert="~{configs/connectionAvailable.html}" th:hx-get="@{/configs?connectionAvailable}" hx-trigger="every 20s"></section>
|
<section hx-ext="sse" th:sse-connect="@{/configs/events}">
|
||||||
|
<div th:insert="~{configs/connectionAvailable.html}" th:hx-get="@{/configs?connectionAvailable}" hx-trigger="sse:connection-available">
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2><span th:if="${not transformations.isEmpty()}">✅</span><span th:if="${transformations.isEmpty()}">⛔</span> Transformationen</h2>
|
<h2><span th:if="${not transformations.isEmpty()}">✅</span><span th:if="${transformations.isEmpty()}">⛔</span> Transformationen</h2>
|
||||||
@ -84,5 +87,6 @@
|
|||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<script th:src="@{/webjars/htmx.org/dist/htmx.min.js}"></script>
|
<script th:src="@{/webjars/htmx.org/dist/htmx.min.js}"></script>
|
||||||
|
<script th:src="@{/webjars/htmx.org/dist/ext/sse.js}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
x
Reference in New Issue
Block a user