diff --git a/CHANGELOG.md b/CHANGELOG.md index 95688f4e2..a492716a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ For changes to the BPDM Helm charts please consult the [changelog](charts/bpdm/C - BPDM Pool: Post endpoint to fetch the BPNL/S/A based on the requested identifiers.([#1052](https://github.com/eclipse-tractusx/bpdm/issues/1052)) - BPDM Gate & Orchestrator: Enhance the error handling mechanism for the orchestrator and gate components by extending the list of available error codes.([#1003](https://github.com/eclipse-tractusx/bpdm/pull/1003#pullrequestreview-2477395867)) - BPDM System Test: Tester module which performs automated end-to-end tests on an existing golden record process.([#1070](https://github.com/eclipse-tractusx/bpdm/pull/1070)) +- Apps : Enhanced dependency readiness checks with a scheduler to verify connections to required services every 30 seconds and during startup for Pool, Cleaning Service Dummy, and Gate service. ([#1161](https://github.com/eclipse-tractusx/bpdm/issues/1161)) ### Changed diff --git a/DEPENDENCIES b/DEPENDENCIES index 510a10f0f..305bb42ae 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -128,7 +128,7 @@ maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-core/10.1.33, Apache-2.0 maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-el/10.1.33, Apache-2.0, approved, #6997 maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-websocket/10.1.33, Apache-2.0, approved, #7920 maven/mavencentral/org.apiguardian/apiguardian-api/1.1.2, Apache-2.0, approved, #17641 -maven/mavencentral/org.aspectj/aspectjweaver/1.9.22.1, Apache-2.0 AND BSD-3-Clause AND EPL-1.0 AND BSD-3-Clause AND Apache-1.1, approved, #15252 +maven/mavencentral/org.aspectj/aspectjweaver/1.9.22.1, EPL-1.0, approved, tools.aspectj maven/mavencentral/org.assertj/assertj-core/3.24.2, Apache-2.0, approved, #6161 maven/mavencentral/org.awaitility/awaitility/4.2.2, Apache-2.0, approved, #14178 maven/mavencentral/org.checkerframework/checker-qual/3.42.0, MIT, approved, clearlydefined diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/CleaningServiceConfigProperties.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/CleaningServiceConfigProperties.kt index 099b6d163..ef4181b44 100644 --- a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/CleaningServiceConfigProperties.kt +++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/CleaningServiceConfigProperties.kt @@ -25,9 +25,14 @@ import org.springframework.boot.context.properties.ConfigurationProperties @ConfigurationProperties(prefix = PREFIX) class CleaningServiceConfigProperties ( - val step: TaskStep + val step: TaskStep, + val dependencyCheck: DependencyCheckConfig ){ companion object{ const val PREFIX = "bpdm.golden-record-process" } + + data class DependencyCheckConfig( + val cron: String = "-" + ) } \ No newline at end of file diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/DependencyHealthScheduler.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/DependencyHealthScheduler.kt new file mode 100644 index 000000000..5043be87c --- /dev/null +++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/DependencyHealthScheduler.kt @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************/ + +package org.eclipse.tractusx.bpdm.cleaning.config + +import jakarta.annotation.PostConstruct +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.cleaning.service.DependencyHealthService +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.TaskScheduler +import org.springframework.scheduling.support.CronTrigger + +@Configuration +class DependencyHealthScheduler( + private val dependencyHealthService: DependencyHealthService, + private val taskScheduler: TaskScheduler, + private val configProperties: CleaningServiceConfigProperties +) { + + private val logger = KotlinLogging.logger { } + + @PostConstruct + fun scheduleHealthChecks() { + taskScheduler.scheduleIfEnabled( + { performHealthCheck() }, + configProperties.dependencyCheck.cron + ) + } + + private fun performHealthCheck() { + val healthStatus = dependencyHealthService.checkAllDependencies() + val unhealthyDependencies = healthStatus.filter { it.value == "Down" } + + if (unhealthyDependencies.isNotEmpty()) { + logger.error("Dependencies not ready: ${unhealthyDependencies.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + } else { + logger.info("All dependencies are healthy: ${healthStatus.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + } + } + + private fun TaskScheduler.scheduleIfEnabled(task: Runnable, cronExpression: String) { + if (cronExpression != "-") { + schedule(task, CronTrigger(cronExpression)) + } + } + +} \ No newline at end of file diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/DependencyHealthService.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/DependencyHealthService.kt new file mode 100644 index 000000000..8367db893 --- /dev/null +++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/DependencyHealthService.kt @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************/ + +package org.eclipse.tractusx.bpdm.cleaning.service + +import org.eclipse.tractusx.bpdm.cleaning.util.OrchestratorHealthIndicator +import org.springframework.boot.actuate.health.Status +import org.springframework.stereotype.Service + +@Service +class DependencyHealthService( + private val orchestratorHealthIndicator: OrchestratorHealthIndicator +) { + + fun checkAllDependencies(): Map { + val orchestratorHealth = if (orchestratorHealthIndicator.health().status == Status.UP) "Healthy" else "Down" + + return mapOf( + "Orchestrator Service" to orchestratorHealth + ) + } +} \ No newline at end of file diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/util/OrchestratorHealthIndicator.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/util/OrchestratorHealthIndicator.kt index 4652758e8..d382fe41d 100644 --- a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/util/OrchestratorHealthIndicator.kt +++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/util/OrchestratorHealthIndicator.kt @@ -34,7 +34,11 @@ class OrchestratorHealthIndicator( override fun health(): Health { val orchestratorHealthUrl = "${orchestratorConfigProperties.baseUrl}/actuator/health" + return try { + /* + Todo: Create new separate REST api end point for orchestrator service which will enable check on health readiness in authenticated way. + */ val response = restTemplate.getForEntity(orchestratorHealthUrl, String::class.java) if (response.statusCode.is2xxSuccessful) { Health.up().withDetail("Orchestrator Service", "Available").build() diff --git a/bpdm-cleaning-service-dummy/src/main/resources/application.yml b/bpdm-cleaning-service-dummy/src/main/resources/application.yml index d22bf3a5a..93491a004 100644 --- a/bpdm-cleaning-service-dummy/src/main/resources/application.yml +++ b/bpdm-cleaning-service-dummy/src/main/resources/application.yml @@ -49,6 +49,9 @@ bpdm: client-secret: "**********" golden-record-process: step: CleanAndSync + dependencyCheck: + # How often the golden record connection dependencies should be checked for being healthy + cron: '*/30 * * * * *' cleaningService: # When and how often the cleaning service should poll for golden record tasks in the orchestrator diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/DependencyHealthScheduler.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/DependencyHealthScheduler.kt new file mode 100644 index 000000000..5b28b09b4 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/DependencyHealthScheduler.kt @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************/ + +package org.eclipse.tractusx.bpdm.gate.config + +import jakarta.annotation.PostConstruct +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.gate.service.DependencyHealthService +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.TaskScheduler +import org.springframework.scheduling.support.CronTrigger + +@Configuration +class DependencyHealthScheduler( + private val dependencyHealthService: DependencyHealthService, + private val taskScheduler: TaskScheduler, + private val configProperties: GoldenRecordTaskConfigProperties +) { + + private val logger = KotlinLogging.logger { } + + @PostConstruct + fun scheduleHealthChecks() { + taskScheduler.scheduleIfEnabled( + { performHealthCheck() }, + configProperties.dependencyCheck.cron + ) + } + + private fun performHealthCheck() { + val healthStatus = dependencyHealthService.checkAllDependencies() + val unhealthyDependencies = healthStatus.filter { it.value == "Down" } + + if (unhealthyDependencies.isNotEmpty()) { + logger.error("Dependencies not ready: ${unhealthyDependencies.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + } else { + logger.info("All dependencies are healthy: ${healthStatus.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + } + } + + private fun TaskScheduler.scheduleIfEnabled(task: Runnable, cronExpression: String) { + if (cronExpression != "-") { + schedule(task, CronTrigger(cronExpression)) + } + } + +} diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/GoldenRecordProcessConfigProperties.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/GoldenRecordProcessConfigProperties.kt index 4f6d474ed..166ab2457 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/GoldenRecordProcessConfigProperties.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/GoldenRecordProcessConfigProperties.kt @@ -25,7 +25,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties data class GoldenRecordTaskConfigProperties( val creation: CreationProperties = CreationProperties(), val check: TaskProcessProperties = TaskProcessProperties(), - val healthCheck: TaskProcessProperties = TaskProcessProperties() + val healthCheck: TaskProcessProperties = TaskProcessProperties(), + val dependencyCheck: TaskProcessProperties = TaskProcessProperties() ) { data class CreationProperties( val fromSharingMember: CreationTaskProperties = CreationTaskProperties(), diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/DependencyHealthService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/DependencyHealthService.kt new file mode 100644 index 000000000..d60d04b0b --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/DependencyHealthService.kt @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************/ + +package org.eclipse.tractusx.bpdm.gate.service + +import org.eclipse.tractusx.bpdm.gate.util.OrchestratorHealthIndicator +import org.eclipse.tractusx.bpdm.gate.util.PoolHealthIndicator +import org.springframework.boot.actuate.health.Status +import org.springframework.stereotype.Service + +@Service +class DependencyHealthService( + private val poolHealthIndicator: PoolHealthIndicator, + private val orchestratorHealthIndicator: OrchestratorHealthIndicator +) { + + fun checkAllDependencies(): Map { + val poolHealth = if (poolHealthIndicator.health().status == Status.UP) "Healthy" else "Down" + val orchestratorHealth = if (orchestratorHealthIndicator.health().status == Status.UP) "Healthy" else "Down" + + return mapOf( + "Pool Service" to poolHealth, + "Orchestrator Service" to orchestratorHealth + ) + } +} diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/GateServiceStartupListener.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/GateServiceStartupListener.kt index d5844234c..0d9c6ce20 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/GateServiceStartupListener.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/GateServiceStartupListener.kt @@ -19,23 +19,29 @@ package org.eclipse.tractusx.bpdm.gate.util -import org.springframework.boot.actuate.health.Status +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.gate.service.DependencyHealthService import org.springframework.boot.context.event.ApplicationReadyEvent import org.springframework.context.ApplicationListener import org.springframework.stereotype.Component @Component class GateServiceStartupListener( - private val poolHealthIndicator: PoolHealthIndicator, - private val orchestratorHealthIndicator: OrchestratorHealthIndicator + private val dependencyHealthService: DependencyHealthService ) : ApplicationListener { + private val logger = KotlinLogging.logger { } + override fun onApplicationEvent(event: ApplicationReadyEvent) { - val poolHealth = poolHealthIndicator.health().status - val orchestratorHealth = orchestratorHealthIndicator.health().status + val healthStatus = dependencyHealthService.checkAllDependencies() + val unhealthyDependencies = healthStatus.filter { it.value == "Down" } - if (poolHealth != Status.UP || orchestratorHealth != Status.UP) { - throw IllegalStateException("Dependencies not ready: Pool: $poolHealth, Orchestrator: $orchestratorHealth") + if (unhealthyDependencies.isNotEmpty()) { + logger.error("Startup failed. Dependencies not ready: ${unhealthyDependencies.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + throw IllegalStateException("Dependencies not ready: ${unhealthyDependencies.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + } else { + logger.info("All dependencies are healthy on startup: ${healthStatus.map { "${it.key}: ${it.value}" }.joinToString(", ")}") } } -} \ No newline at end of file + +} diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/OrchestratorHealthIndicator.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/OrchestratorHealthIndicator.kt index 133acb2d5..b9057c6c3 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/OrchestratorHealthIndicator.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/OrchestratorHealthIndicator.kt @@ -19,24 +19,28 @@ package org.eclipse.tractusx.bpdm.gate.util -import org.eclipse.tractusx.bpdm.gate.config.OrchestratorClientConfigurationProperties +import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest +import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient import org.springframework.boot.actuate.health.Health import org.springframework.boot.actuate.health.HealthIndicator import org.springframework.stereotype.Component -import org.springframework.web.client.RestTemplate +import java.time.Instant @Component("orchestratorHealth") class OrchestratorHealthIndicator( - private val restTemplate: RestTemplate, - private val orchestratorClientProperties: OrchestratorClientConfigurationProperties + private val orchestrationClient: OrchestrationApiClient ) : HealthIndicator { override fun health(): Health { - val orchestratorHealthUrl = "${orchestratorClientProperties.baseUrl}/actuator/health" return try { - val response = restTemplate.getForEntity(orchestratorHealthUrl, String::class.java) - if (response.statusCode.is2xxSuccessful) { + /* + We can directly use actuator heath response from Orchestrator service but that will not be an authenticated way. + So, included get finished task events request to achieve the same for now and in future we can create separate REST api endpoint which will provide + health of the service with readiness in authenticated way. + */ + val response = orchestrationClient.finishedTaskEvents.getEvents(Instant.now(), PaginationRequest(page = 0, size = 1)) + if (response.contentSize >= 0) { Health.up().withDetail("Orchestrator Service", "Available").build() } else { Health.down().withDetail("Orchestrator Service", "Unreachable").build() diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/PoolHealthIndicator.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/PoolHealthIndicator.kt index a2a5df835..26b7a034d 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/PoolHealthIndicator.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/PoolHealthIndicator.kt @@ -19,24 +19,28 @@ package org.eclipse.tractusx.bpdm.gate.util -import org.eclipse.tractusx.bpdm.gate.config.PoolClientConfigurationProperties +import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest +import org.eclipse.tractusx.bpdm.pool.api.client.PoolApiClient +import org.eclipse.tractusx.bpdm.pool.api.model.request.ChangelogSearchRequest import org.springframework.boot.actuate.health.Health import org.springframework.boot.actuate.health.HealthIndicator import org.springframework.stereotype.Component -import org.springframework.web.client.RestTemplate @Component("poolHealth") class PoolHealthIndicator( - private val restTemplate: RestTemplate, - private val poolClientProperties: PoolClientConfigurationProperties + private val poolClient: PoolApiClient, ) : HealthIndicator { override fun health(): Health { - val poolHealthUrl = "${poolClientProperties.baseUrl}/actuator/health" return try { - val response = restTemplate.getForEntity(poolHealthUrl, String::class.java) - if (response.statusCode.is2xxSuccessful) { + /* + We can directly use actuator heath response from Pool service but that will not be an authenticated way. + So, included changelog request to achieve the same for now and in future we can create separate REST api endpoint which will provide + health of the service with readiness in authenticated way. + */ + val response = poolClient.changelogs.getChangelogEntries(ChangelogSearchRequest(), PaginationRequest(page = 0, size = 1)) + if (response.contentSize >= 0) { Health.up().withDetail("Pool Service", "Available").build() } else { Health.down().withDetail("Pool Service", "Unreachable").build() diff --git a/bpdm-gate/src/main/resources/application.yml b/bpdm-gate/src/main/resources/application.yml index 295a46e02..7dbfc7573 100644 --- a/bpdm-gate/src/main/resources/application.yml +++ b/bpdm-gate/src/main/resources/application.yml @@ -64,6 +64,9 @@ bpdm: batchSize: 1000 # How often the golden record tasks should be checked for being healthy cron: '0 0 0 * * *' + dependencyCheck: + # How often the golden record connection dependencies should be checked for being healthy + cron: '*/30 * * * * *' # Connection to the pool and orchestrator client: diff --git a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/config/DependencyHealthScheduler.kt b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/config/DependencyHealthScheduler.kt new file mode 100644 index 000000000..17a423c46 --- /dev/null +++ b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/config/DependencyHealthScheduler.kt @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************/ + +package org.eclipse.tractusx.bpdm.pool.config + +import jakarta.annotation.PostConstruct +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.pool.service.DependencyHealthService +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.TaskScheduler +import org.springframework.scheduling.support.CronTrigger + +@Configuration +class DependencyHealthScheduler( + private val dependencyHealthService: DependencyHealthService, + private val taskScheduler: TaskScheduler, + private val configProperties: GoldenRecordTaskConfigProperties +) { + + private val logger = KotlinLogging.logger { } + + @PostConstruct + fun scheduleHealthChecks() { + taskScheduler.scheduleIfEnabled( + { performHealthCheck() }, + configProperties.cron + ) + } + + private fun performHealthCheck() { + val healthStatus = dependencyHealthService.checkAllDependencies() + val unhealthyDependencies = healthStatus.filter { it.value == "Down" } + + if (unhealthyDependencies.isNotEmpty()) { + logger.error("Dependencies not ready: ${unhealthyDependencies.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + } else { + logger.info("All dependencies are healthy: ${healthStatus.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + } + } + + private fun TaskScheduler.scheduleIfEnabled(task: Runnable, cronExpression: String) { + if (cronExpression != "-") { + schedule(task, CronTrigger(cronExpression)) + } + } + +} \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/AppConfig.kt b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/DependencyHealthService.kt similarity index 60% rename from bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/AppConfig.kt rename to bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/DependencyHealthService.kt index 861bc0300..b3a299639 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/AppConfig.kt +++ b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/DependencyHealthService.kt @@ -17,17 +17,22 @@ * SPDX-License-Identifier: Apache-2.0 ******************************************************************************/ -package org.eclipse.tractusx.bpdm.gate.config +package org.eclipse.tractusx.bpdm.pool.service -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.web.client.RestTemplate +import org.eclipse.tractusx.bpdm.pool.util.OrchestratorHealthIndicator +import org.springframework.boot.actuate.health.Status +import org.springframework.stereotype.Service -@Configuration -class AppConfig { +@Service +class DependencyHealthService( + private val orchestratorHealthIndicator: OrchestratorHealthIndicator +) { - @Bean - fun restTemplate(): RestTemplate { - return RestTemplate() + fun checkAllDependencies(): Map { + val orchestratorHealth = if (orchestratorHealthIndicator.health().status == Status.UP) "Healthy" else "Down" + + return mapOf( + "Orchestrator Service" to orchestratorHealth + ) } -} \ No newline at end of file +} diff --git a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/util/OrchestratorHealthIndicator.kt b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/util/OrchestratorHealthIndicator.kt index 7ad6fabcd..bd036984a 100644 --- a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/util/OrchestratorHealthIndicator.kt +++ b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/util/OrchestratorHealthIndicator.kt @@ -19,22 +19,30 @@ package org.eclipse.tractusx.bpdm.pool.util +import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest import org.eclipse.tractusx.bpdm.pool.config.OrchestratorClientConfigProperties +import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient +import org.eclipse.tractusx.orchestrator.api.model.TaskStateRequest import org.springframework.boot.actuate.health.Health import org.springframework.boot.actuate.health.HealthIndicator import org.springframework.stereotype.Component import org.springframework.web.client.RestTemplate +import java.time.Instant @Component("orchestratorHealth") class OrchestratorHealthIndicator( private val restTemplate: RestTemplate, - private val orchestratorClientProperties: OrchestratorClientConfigProperties + private val orchestratorConfigProperties: OrchestratorClientConfigProperties ) : HealthIndicator { override fun health(): Health { - val orchestratorHealthUrl = "${orchestratorClientProperties.baseUrl}/actuator/health" + val orchestratorHealthUrl = "${orchestratorConfigProperties.baseUrl}/actuator/health" + return try { + /* + Todo: Create new separate REST api end point for orchestrator service which will enable check on health readiness in authenticated way. + */ val response = restTemplate.getForEntity(orchestratorHealthUrl, String::class.java) if (response.statusCode.is2xxSuccessful) { Health.up().withDetail("Orchestrator Service", "Available").build() diff --git a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/util/PoolServiceStartupListner.kt b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/util/PoolServiceStartupListner.kt index 4fa864316..c7a2803d9 100644 --- a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/util/PoolServiceStartupListner.kt +++ b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/util/PoolServiceStartupListner.kt @@ -19,21 +19,28 @@ package org.eclipse.tractusx.bpdm.pool.util -import org.springframework.boot.actuate.health.Status +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.pool.service.DependencyHealthService import org.springframework.boot.context.event.ApplicationReadyEvent import org.springframework.context.ApplicationListener import org.springframework.stereotype.Component @Component class PoolServiceStartupListner( - private val orchestratorHealthIndicator: OrchestratorHealthIndicator + private val dependencyHealthService: DependencyHealthService ) : ApplicationListener { + private val logger = KotlinLogging.logger { } + override fun onApplicationEvent(event: ApplicationReadyEvent) { - val orchestratorHealth = orchestratorHealthIndicator.health().status + val healthStatus = dependencyHealthService.checkAllDependencies() + val unhealthyDependencies = healthStatus.filter { it.value == "Down" } - if (orchestratorHealth != Status.UP) { - throw IllegalStateException("Dependencies not ready: Orchestrator: $orchestratorHealth") + if (unhealthyDependencies.isNotEmpty()) { + logger.error("Startup failed. Dependencies not ready: ${unhealthyDependencies.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + throw IllegalStateException("Dependencies not ready: ${unhealthyDependencies.map { "${it.key}: ${it.value}" }.joinToString(", ")}") + } else { + logger.info("All dependencies are healthy on startup: ${healthStatus.map { "${it.key}: ${it.value}" }.joinToString(", ")}") } }