Generalisation of single or compound health checks
ludovicc opened this issue · 3 comments
Hello,
I find it hard to generalise between single health checks of type HealthCheck[F, TaggedS]
and compound checks of type HealthReporter[F, NonEmptyList, TaggedS]
where type TaggedS[H] = Tagged[String, H]
I just want to call the check and report errors, but the different types seem to go in the way. Can you propose a better solution than this code duplication?
Thanks
def dbHealth: Route = pathPrefix("db") {
pathEndOrSingleSlash {
get {
// type TaggedS[H] = Tagged[String, H]
// healthChecks: HealthReporter[F, NonEmptyList, TaggedS]
onComplete(runLater(databaseServices.healthChecks.check)) {
case Success(checks) =>
if (checks.value.health.isHealthy)
complete(OK)
else
complete((StatusCodes.InternalServerError, checks.value.show))
case Failure(ex) =>
complete((InternalServerError, s"An error occurred: ${ex.getMessage}"))
}
}
} ~ featuresDbHealth ~ metaDbHealth ~ wokenDbHealth
}
private def performCheck(check: HealthCheck[F, TaggedS]): Route =
onComplete(runLater(check.check)) {
case Success(checks) =>
if (checks.value.health.isHealthy)
complete(OK)
else
complete((StatusCodes.InternalServerError, checks.value.show))
case Failure(ex) =>
complete((InternalServerError, s"An error occurred: ${ex.getMessage}"))
}
https://github.com/LREN-CHUV/woken/blob/master/src/main/scala/ch/chuv/lren/woken/api/MonitoringWebService.scala#L182
https://github.com/LREN-CHUV/woken/blob/master/src/main/scala/ch/chuv/lren/woken/api/MonitoringWebService.scala#L217
Off the top of my head, you should be able to abstract on the container type of your HealthCheck like HealthCheck[F, Lambda[A => G[TaggedS[A]]]]
, and most functions like isHealthy
would work if G[_]: Foldable
. In case you need more info or anything turns out not to be true (I haven't looked at sup in a while), I'll get back to this and look for alternatives.
This seems to compile in your case:
private def performCheck[G[_]: cats.Foldable](check: HealthCheck[F, G])(implicit show: cats.Show[G[sup.Health]]): Route =
onComplete(runLater(check.check)) {
case Success(checks) =>
if (checks.value.combineAll.isHealthy)
complete(OK)
else
complete((StatusCodes.InternalServerError, checks.value.show))
case Failure(ex) =>
complete((InternalServerError, s"An error occurred: ${ex.getMessage}"))
}
I think I might also be missing an implicit Show[G[Health]] => Show[HealthResult[G]]
instance that'd make this a tiny bit more helpful. And it'd be much nicer if we had a higher-kinded, universally quantified Show[G[a] forall a]
...
(do consider some json encoder like Circe's instead of Show though)
Let me know if doesn't work :) in fact, if it does and you want to contribute, I'd accept a PR with routing code like the http4s module (https://github.com/kubukoz/sup/blob/master/modules/http4s/src/main/scala/sup/modules/http4s.scala#L34)
I'll close this issue for now. If you still have problems generalizing the code, feel free to ping me again and reopen this :)