Hey Folks, we are running a little Webflux servic...
# spring
d
Hey Folks, we are running a little Webflux service in our team. We use
kotlinx.coroutins.reactor
package to bridge both worlds (reactive -> Coroutines). Now we want to build an custom
ReactiveHealthIndicator
. Therefore we inherit this interface
ReactiveHealthIndicator
from
package org.springframework.boot.actuate.health
which expects to implement an method with the signature of
fun health(): Mono<Health>
. So far, so good. The problem is that we need to call an suspending function Inside the
health()
method. Here is a little snippet, which should explain the problem a bit further:
Copy code
@Component
class ClientHealthIndicator(private val client: SomeClient) : ReactiveHealthIndicator {
    private val logger = KotlinLogging.logger { }
    override fun health(): Mono<Health> =
        try {
            client.getPage("home") // THIS IS THE SUSPEND FUNCTION
            Health.up().build().let { Mono.just(it) }
        } catch (e: Exception) {
            logger.error(e) { "ContentClient health check failed" }
            Health.down(e).build().let { Mono.just(it) }
        }
}
We tried to use the MonoCoroutine Builder function from
kotlinx.coroutins.reactor
to build an scope which returns a Mono.
Copy code
@Component
class ContentClientHealthIndicator(private val contentJsonClient: ContentJsonClient) : ReactiveHealthIndicator {
    private val logger = KotlinLogging.logger { }
    override fun health(): Mono<Health> = mono {
        try {
            contentJsonClient.getPage(it)
            Health.up().build()
        } catch (e: Exception) {
            logger.error(e) { "ContentClient health check failed" }
            Health.down(e).build()
        }
    }
}
This does look good, but fails as fullfiling solution because the only thing that get´s catched is this:
kotlinx.coroutines.JobCancellationException: MonoCoroutine was cancelled
I am a bit helpless here and would appreciate any help. Thanks in advance Dennis
n
How does your contentJsonClient.getPage looks like?
d
Copy code
override suspend fun getPage(slug: String): Page =
    try {
        s3Client
            .getObject(bucketName = bucketName, fileName = "$slug.json")
            .mapToObject(mapper)
    } catch (e: NoSuchBucketException) {
        throw BucketNotFoundException("No matching bucket found.", bucketName)
    } catch (e: NoSuchKeyException) {
        throw PageNotFoundException("Page with slug: \"$slug\" not found.", slug)
And here is the s3Client
Copy code
suspend fun getObject(bucketName: String, fileName: String): ByteArray {
    val request = GetObjectRequest.builder().bucket(bucketName).key(fileName).build()

    return client.getObject(request, AsyncResponseTransformer.toBytes()).await()?.asByteArray()
        ?: throw IllegalStateException("S3 GetObjectRequest is null without exception")
}
a
shouldn't you await your suspend function?
a
folks did you find any solution to this?
203 Views