Skip to content

Commit dc61839

Browse files
authored
fix(postgres): probe over TCP so dependents aren't released early (#152)
postgres' docker-entrypoint runs a temporary server reachable only over the Unix socket (listen_addresses='') once initdb has finished, so it can create the database and run docker-entrypoint-initdb.d. A pg_isready probe without -h talks to that socket, so it answers "accepting connections" while no TCP listener exists at all. compose then marks the service healthy and depends_on: service_healthy releases the dependent straight into ECONNREFUSED. Measured at ~235ms with no initdb.d scripts, and at 1.2s of false-healthy followed by a 2.7s shutdown checkpoint in the CI failure this was diagnosed from. Reproduced on postgres 13.3, 15 and 16. Only bites on a fresh volume, since a populated one skips the temporary server entirely -- which is why it surfaced as a rare flake rather than a consistent failure. Passing -h 127.0.0.1 forces a TCP probe, which tracks the real listener in every phase: the stock images ship listen_addresses = '*', and during startup or recovery pg_isready reports "rejecting connections", so the probe correctly keeps failing until the server can actually serve. The k8s manifest gets the same change on its readinessProbe only. The livenessProbe deliberately keeps the socket check: liveness asks whether the process is alive and a failure restarts the pod, so a TCP probe there would restart-loop a pod whose initdb outruns initialDelaySeconds + failureThreshold * periodSeconds. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
1 parent 2718589 commit dc61839

3 files changed

Lines changed: 40 additions & 3 deletions

File tree

ps-cache-kotlin/docker-compose.yml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,21 @@ services:
1111
- pgdata:/var/lib/postgresql/data
1212
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
1313
healthcheck:
14-
test: ["CMD-SHELL", "pg_isready -U postgres"]
14+
# -h 127.0.0.1 is load-bearing: it forces a TCP probe.
15+
#
16+
# Without it pg_isready talks to the Unix socket, and postgres'
17+
# docker-entrypoint runs a *temporary* server reachable only over that
18+
# socket (listen_addresses='') once initdb has finished, to create the
19+
# database and run docker-entrypoint-initdb.d. The socket therefore
20+
# answers "accepting connections" while no TCP listener exists at all,
21+
# so compose marks this service healthy and depends_on:
22+
# service_healthy releases the dependent straight into ECONNREFUSED.
23+
#
24+
# Short but real: ~235ms with no initdb.d scripts, and 1.2s of
25+
# false-healthy plus a 2.7s shutdown checkpoint in the CI failure this
26+
# was diagnosed from. Only bites on a fresh volume -- a populated one
27+
# skips the temporary server entirely, which is why it failed rarely.
28+
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U postgres"]
1529
interval: 2s
1630
timeout: 5s
1731
retries: 5

sap-demo-java/docker-compose.yml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,21 @@ services:
1717
volumes:
1818
- pgdata:/var/lib/postgresql/data
1919
healthcheck:
20-
test: ["CMD", "pg_isready", "-U", "customer360", "-d", "customer360"]
20+
# -h 127.0.0.1 is load-bearing: it forces a TCP probe.
21+
#
22+
# Without it pg_isready talks to the Unix socket, and postgres'
23+
# docker-entrypoint runs a *temporary* server reachable only over that
24+
# socket (listen_addresses='') once initdb has finished, to create the
25+
# database and run docker-entrypoint-initdb.d. The socket therefore
26+
# answers "accepting connections" while no TCP listener exists at all,
27+
# so compose marks this service healthy and depends_on:
28+
# service_healthy releases customer360 straight into ECONNREFUSED.
29+
#
30+
# Short but real: ~235ms with no initdb.d scripts, and 1.2s of
31+
# false-healthy plus a 2.7s shutdown checkpoint in the CI failure this
32+
# was diagnosed from. Only bites on a fresh volume -- a populated one
33+
# skips the temporary server entirely, which is why it failed rarely.
34+
test: ["CMD", "pg_isready", "-h", "127.0.0.1", "-U", "customer360", "-d", "customer360"]
2135
interval: 5s
2236
timeout: 3s
2337
retries: 10

sap-demo-java/k8s/postgres.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,21 @@ spec:
8888
cpu: "500m"
8989
memory: "256Mi"
9090
readinessProbe:
91+
# Readiness means "can serve clients", so probe over TCP.
92+
# Without -h, pg_isready uses the Unix socket, which the
93+
# temporary post-initdb server (listen_addresses='') already
94+
# answers -- marking the pod Ready while no TCP listener exists
95+
# and letting dependents connect to a refused port.
9196
exec:
92-
command: ["pg_isready", "-U", "customer360", "-d", "customer360"]
97+
command: ["pg_isready", "-h", "127.0.0.1", "-U", "customer360", "-d", "customer360"]
9398
periodSeconds: 5
9499
timeoutSeconds: 3
95100
failureThreshold: 5
96101
livenessProbe:
102+
# Deliberately the socket probe, unlike readiness above: liveness
103+
# asks "is the process alive", and a failure restarts the pod. A
104+
# TCP probe here would restart-loop a pod whose initdb outruns
105+
# initialDelaySeconds + failureThreshold * periodSeconds.
97106
exec:
98107
command: ["pg_isready", "-U", "customer360", "-d", "customer360"]
99108
initialDelaySeconds: 15

0 commit comments

Comments
 (0)