Repository navigation
Add health endpoints for observability - #62
Merged
Merged
Conversation
An uptime monitor had nothing to poll but a page render, which costs a database round trip, a template render and an external feed lookup just to answer "is it up". quarkus-smallrye-health answers that directly, and quarkus-agroal contributes the datasource readiness check by itself, so no hand-written HealthCheck is needed. The endpoints stay anonymous on the main port so a monitor can reach them without a Keycloak client. That is exactly what makes them easy to break: with oidc.application-type=web-app, a probe path pulled into quarkus.http.auth.permission answers 302 to Keycloak instead of a status, which a monitor checking only for "a response" would happily accept. The test therefore refuses to follow redirects, and it asserts that readiness carries at least one check -- disabling the datasource check would leave a probe that reports UP while testing nothing. The events feed is deliberately left out: it is a third-party URL, and a readiness probe going red on someone else's hiccup would take an app out of rotation that still serves every page from the 5-minute cache. Signed-off-by: Niko Köbler <niko@n-k.de>
depends_on alone only waits for the container to exist, not for Postgres to accept connections, so the app could come up first and have Flyway fail its migration at start against a database that was not listening yet. A pg_isready healthcheck plus condition: service_healthy closes that race. The app gets a healthcheck of its own against /q/health/ready, which is what makes "unhealthy" visible in docker ps. Compose does not restart an unhealthy container by itself -- this buys ordering and visibility, not self-healing. curl is used because the ubi9/openjdk-25-runtime image ships it and has no wget. Signed-off-by: Niko Köbler <niko@n-k.de>
The two decisions that are invisible in the diff: the endpoints must stay out of quarkus.http.auth.permission (a secured probe answers 302, not a status), and the external events feed is intentionally not part of readiness. closes #61 Signed-off-by: Niko Köbler <niko@n-k.de>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #61.
quarkus-smallrye-healthexposes/q/health,/q/health/live,/q/health/readyand/q/health/started. No hand-writtenHealthCheckwas needed:quarkus-agroalcontributes thedatasource readiness check by itself, and that is the one thing worth probing here.
What is in it
pom.xml— thequarkus-smallrye-healthdependency.HealthCheckTest— pins the two ways these endpoints break silently (see below).docker-compose.yml—pg_isreadyon the database,curl -f .../q/health/readyon the app,and
depends_on: condition: service_healthyin place of a baredepends_on: database.CLAUDE.md/README.adoc— the endpoints and the reasoning. The README embedsdocker-compose.ymlviainclude::, so the healthchecks show up there automatically.Two decisions worth reviewing
The endpoints are anonymous, on the main port. That is what lets an external uptime monitor
reach them without a Keycloak client. It also means they have to stay out of
quarkus.http.auth.permission: withquarkus.oidc.application-type=web-app, a secured probe pathanswers 302 to Keycloak rather than a status, and a monitor that only checks "did I get a
response" would never notice. The test refuses to follow redirects for exactly that reason.
The external events feed is deliberately not part of readiness.
EventServiceloads eachtenant's events JSON from a third-party URL. A probe going red on someone else's hiccup would pull
an app out of rotation that still serves every page from the 5-minute Caffeine cache. Feed failures
belong in the log.
Verification
Both test assertions were mutation-checked rather than assumed:
quarkus.http.auth.permissiononto/q/health*→Expected status code <200> but was <302>-Dquarkus.datasource.health.enabled=false→JSON path checks doesn't matchpg_isready -U registration -d registrationwas verified against a throwawaypostgres:18-alpinecontainer (
exit=0 ... accepting connections),curlwas confirmed present inubi9/openjdk-25-runtime:1.24(nowget), anddocker compose config -qvalidates.Full suite: 49 tests, 0 failures.