Skip to main content

Management endpoints and ports reference

Endpoints​

Riptide serves plain-HTTP endpoints on a management port, with no auth and no TLS, for cluster-internal use. They are built on the JDK HTTP server, so the collector stays headless.

EndpointMeaningAnswers
GET /livezLiveness: the receiver event loops are alive. Never checks ClickHouse.200 while booting and once running; 503 only if a started receiver's socket has died
GET /readyzReadiness: all configured receivers are bound and listening. Zero configured receivers reports ready.200 ok: receivers listening, else 503 receivers not listening: <names>
GET /metricsThe full metric registry in Prometheus text format.200, or 404 with riptide.management.metrics-enabled=false
curl -s -i http://localhost:8080/readyz

Expected output:

HTTP/1.1 200 OK
Date: Wed, 23 Sep 2026 12:37:07 GMT
Content-type: text/plain; charset=utf-8
Content-length: 24

ok: receivers listening

Readiness excludes ClickHouse. Flows arrive as UDP push, so a "not ready" collector does not stop the packets; it only moves the loss to another layer, a drained load balancer under externalTrafficPolicy: Local or the wire. When ClickHouse recovers, readiness convergence typically loses more flows than the bounded batching queue (riptide.clickhouse.batch.queue-capacity, 40,000 rows by default) absorbs: at the measured ~11.8k rows/s the queue covers ~3.4 s, well under a probe period plus endpoint propagation. Where Prometheus scrapes through the Service, "not ready" can also remove the pod from the endpoints and take /metrics down with it, blinding the one signal that explains the outage. A ClickHouse outage therefore keeps the collector receiving. Probes are for scheduling; saturation is for alerting: watch a sustained persister.batch.droppedRows or persister.batch.failedRows rate and persister.batch.queueDepth approaching the queue capacity. A non-zero persister.batch.deadLetterFailedRows rate is a separate signal: the refused rows are not being kept anywhere.

Readiness tolerates zero configured receivers because the shipped configuration declares none, so failing readiness there would turn a fresh install into a pod that never becomes ready. A collector without receivers logs a startup WARN (No receivers configured) and reports ready: misconfigured, not unhealthy.

Receivers start after the ClickHouse startup wait, so /readyz answers 503 for as long as a backend keeps it waiting, up to riptide.clickhouse.startup-wait (30 s by default). That default sits under both probe budgets below: the startupProbe allows 30 × 2 s = 60 s, and the compose healthcheck allows start_period: 20s plus 3 × 10 s. Raise the wait and raise those with it, or the orchestrator restarts a collector that was about to come up.

Settings​

NameTypeDefaultDescription
riptide.management.enabledbooleantruefalse disables the endpoints entirely.
riptide.management.portint8080Listening port.
riptide.management.bind-addressstring0.0.0.0Bind address.
riptide.management.metrics-enabledbooleantruefalse serves the probes but does not register /metrics, so a scrape gets 404. Probes answer up/down; metrics describe your exporters and throughput, which is why the two are separate.
riptide.management.max-concurrent-requestsint32Requests in flight across all three endpoints. Requests beyond the cap are answered 503 rather than queued, so a probe gets a fast answer instead of waiting behind a burst.

The endpoints are served on virtual threads. jstack does not show virtual threads, so the management-http-* handlers are invisible to it and to top -H; their absence from a thread dump means the server is idle, not dead. To see them, take a dump that includes virtual threads:

jcmd <pid> Thread.dump_to_file -format=json /tmp/threads.json

Probe mapping​

Kubernetes:

startupProbe: { httpGet: { path: /readyz, port: 8080 }, failureThreshold: 30, periodSeconds: 2 }
livenessProbe: { httpGet: { path: /livez, port: 8080 } }
readinessProbe: { httpGet: { path: /readyz, port: 8080 } }

The compose stack uses /readyz as the service healthcheck, through the image's BusyBox wget:

healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/readyz"]
interval: 10s
timeout: 3s
retries: 3
start_period: 20s

Metrics endpoint​

GET /metrics renders the whole metric registry in Prometheus text exposition format 0.0.4.

curl -s http://localhost:8080/metrics | grep -E '^(# TYPE )?persister_batch'

Expected output:

# TYPE persister_batch_queueDepth gauge
persister_batch_queueDepth 0.0
# TYPE persister_batch_deadLetterFailedRows counter
persister_batch_deadLetterFailedRows 0.0
# TYPE persister_batch_deadLetteredRows counter
persister_batch_deadLetteredRows 0.0
# TYPE persister_batch_droppedRows counter
persister_batch_droppedRows 0.0
# TYPE persister_batch_failedRows counter
persister_batch_failedRows 0.0
# TYPE persister_batch_batchSize summary
persister_batch_batchSize{quantile="0.5"} 0.0

Registry names contain dots; Prometheus metric names may not. Characters outside [a-zA-Z0-9_:] are replaced with _, so enrichment.optionInterfaces.consumed is scraped as enrichment_optionInterfaces_consumed. Counters are not given the conventional _total suffix, so a name you find in the source is the name you search for in Grafana. The metrics reference lists every series by its registry name.

Registry typeExposed as
Gauge (numeric)gauge. Non-numeric gauges are skipped: they have no valid representation, and emitting one would break the entire scrape rather than one series.
Countercounter
Metercounter, plus _rate_1m and _rate_5m gauges carrying Dropwizard's own moving averages
Histogramsummary with p50/p95/p99 and _count
Timersummary named <name>_seconds with p50/p95/p99 and _count. Durations are converted from nanoseconds to seconds.

The endpoint shares the probes' concurrency cap rather than having its own. Rendering walks the whole registry, so it is the more expensive handler and has more reason to be bounded. A scrape that loses the race is shed with 503, which Prometheus records as a failed scrape.

Ports​

PortProtocolWhat
9999/udpNetFlow/IPFIXdefault flow ingest (container EXPOSE; receivers are configurable)
8080HTTPmanagement endpoints (/livez, /readyz, /metrics); riptide.management.port
8123HTTPClickHouse (the compose stack publishes it on loopback only; password from CLICKHOUSE_PASSWORD)
9000TCPClickHouse native protocol (the compose stack publishes it on loopback only)

Image tags​

TagMeaningUse for
:<version>immutable releaseproduction (pin this)
:X.Ynewest patch release of that minor; moves on every release of ittracking a minor
:latestnewest releasequickstarts
:rcfloating, rebuilt on every merge to maintracking development, at your own risk

Open questions​

  • The 503 bodies were not captured: the local run had no receiver whose socket could die, and no ClickHouse that kept the startup wait open.