Skip to content

Readiness API

Philip Helger edited this page Sep 1, 2026 · 2 revisions

The readiness API was introduced in v8.4.0 upon request #529. It adds the relative URL /smp-ready to the SMP server to query whether the SMP can currently serve requests using its configured backend. It MUST be accessed with HTTP GET.

The response is a UTF-8 encoded JSON document with MIME type application/json:

HTTP status Body Meaning
200 {"ready":true} The configured backend is usable - the SMP can serve requests
503 {"ready":false} The backend is currently unavailable - the SMP cannot serve requests

The endpoint deliberately returns nothing but this boolean. It is meant to be consumed by an infrastructure component - not by a human - and it is reachable without authentication, so it must not disclose why the SMP is not ready. Use the Status API for diagnostics instead.

Difference to /ping and /smp-status

phoss SMP offers three different endpoints for monitoring, and they answer three different questions:

Endpoint Question Typical use
/ping Is the process alive and is the web application responding? Kubernetes livenessProbe
/smp-ready Can the SMP currently serve requests with its backend? Kubernetes readinessProbe
/smp-status/ How is this SMP configured? Diagnostics, monitoring dashboards

The distinction between /ping and /smp-ready matters:

  • Using a backend dependent check as the liveness probe creates a restart loop during a temporary database outage - the container is killed although nothing is wrong with it.
  • Using /ping alone as the readiness probe keeps routing traffic to a pod whose database is unavailable, so the requests fail.

/smp-status/ is not a substitute for /smp-ready, because it answers HTTP 200 even when a backend specific check reports an unusable dependency, and because it is disabled by default via smp.status.enabled.

Backend specific checks

Every backend provides exactly one implementation of the SPI interface com.helger.phoss.smp.ready.ISMPReadyProviderExtensionSPI:

  • XML - always ready. The backend has no external dependency that could be unavailable.
  • SQL - a connection is taken from the connection pool and validated. The validation is required, because the pool hands out pooled connections without checking them, as long as jdbc.pooling.test-on-borrow is disabled (which is the default). Without the validation, a database that died after the connection was pooled would still be reported as usable.
  • MongoDB - the live writable state that the MongoDB driver maintains through its cluster listener. This is a cached flag, so the check performs no I/O at all.

If no implementation is found, the SMP reports itself as not ready and logs an error on startup. That way a backend that does not declare its readiness cannot be mistaken for a healthy one. So if you implement a custom backend, provide an implementation of this SPI interface as well.

Time limit

A readiness request must never block an HTTP thread indefinitely. The readiness checks are therefore executed with a time limit, configurable via the Configuration property smp.ready.timeout (default 2 seconds). If the checks do not finish in time, the SMP is reported as not ready.

This is not a theoretical concern: if a database becomes silently unreachable - the TCP connection stays open but no answer is ever returned - then DataSource.getConnection() blocks indefinitely, well beyond the jdbc.pooling.max-wait setting. Without the time limit, every readiness request would occupy an HTTP thread until the operating system eventually drops the connection.

Kubernetes example

livenessProbe:
  httpGet:
    path: /ping
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3
readinessProbe:
  httpGet:
    path: /smp-ready
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 10
  timeoutSeconds: 3
  failureThreshold: 2

Note that timeoutSeconds of the readiness probe should be larger than the configured smp.ready.timeout, so that the SMP gets the chance to answer {"ready":false} itself instead of the probe running into its own timeout.

If the SMP runs with a context path (i.e. smp.forceroot is not used), the probe paths must be prefixed with that context path.

Clone this wiki locally