Skip to content

Commit 0c64e28

Browse files
committed
deploy: let the probe try every provider it discovers
The first hub deploy with the probe failed at the last step: discovery returned three providers for the everything service and the probe took the first, a peer id from a pod the rollout had just replaced. The egress gate could not reach it to verify its credential and answered 403 "destination is not an enrolled peer". The scheduled runs since show the same coin toss: whichever of the two stale records lists first fails the run, the live pod passes it. A provider record naming a pod that is gone is mesh life, not a fault -- the docs already tell agents that discovery is best-effort per peer -- so the probe now behaves like an agent should: every discovered provider is tried, the whole discover-and-call is retried for up to two minutes, and the run reports how long a live provider took to reach and how many were tried. The Job deadline and the deploy step's wait grow to match. Reproduced in kind by rolling the everything canary under the probe: ready in 2s, live provider reached after 51s, initialize in 9ms.
1 parent 849895e commit 0c64e28

2 files changed

Lines changed: 32 additions & 23 deletions

File tree

.github/k8s/sam-probe-cronjob-template.yaml

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ spec:
1919
# One attempt: a retry would hide exactly the flakiness this exists to
2020
# measure. A failed Job is the signal.
2121
backoffLimit: 0
22-
activeDeadlineSeconds: 300
22+
# 180s to be ready plus 120s to reach a provider, with headroom.
23+
activeDeadlineSeconds: 360
2324
template:
2425
metadata:
2526
labels:
@@ -118,35 +119,43 @@ spec:
118119
ROUTER_MS=$(printf '%s' "$CONN" | grep -oE '"router_latency_ms":[0-9]+' | grep -oE '[0-9]+$')
119120
PEERS=$(printf '%s' "$CONN" | grep -oE '"connected_peers":[0-9]+' | grep -oE '[0-9]+$')
120121
121-
# 3. A service someone else advertised is discoverable. A node
122-
# that joined seconds ago has a thin routing table, so the lookup
123-
# is retried for a while; how long it takes is itself reported.
122+
# 3. A service someone else advertised is discoverable, and one
123+
# of its providers answers an MCP initialize through the mesh.
124+
# Discovery is best-effort per peer: a provider record can name a
125+
# pod that a rollout just replaced, and a node that joined
126+
# seconds ago has a thin routing table. So every provider is
127+
# tried, the whole thing is retried for a while, and how long it
128+
# took is itself reported. No trailing slash on the call: the
129+
# path maps onto the service's target_url as-is. The body is JSON
130+
# or an SSE frame; either names the server.
124131
PEER=""
125-
DISCOVER_START=$(date +%s)
132+
TRIED=0
133+
LAST_ERR=""
134+
REACH_START=$(date +%s)
126135
while [ -z "$PEER" ]; do
127136
if curl -sf --unix-socket "$SOCK" -o /tmp/providers.json \
128137
"http://localhost/sam/service/discover?type=mcp&name=${PROBE_SERVICE}&timeout=20s"; then
129-
PEER=$(grep -oE '"peer_id":"[^"]+"' /tmp/providers.json | head -1 | cut -d'"' -f4)
138+
for p in $(grep -oE '"peer_id":"[^"]+"' /tmp/providers.json | cut -d'"' -f4); do
139+
TRIED=$((TRIED + 1))
140+
set -- $(curl -s --unix-socket "$SOCK" -o /tmp/init.out -w '%{http_code} %{time_total}' \
141+
-X POST "http://localhost/sam/${p}/mcp/${PROBE_SERVICE}" \
142+
-H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
143+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"sam-probe","version":"0"}}}')
144+
if [ "$1" = "200" ] && grep -q '"serverInfo"' /tmp/init.out; then
145+
PEER=$p; CALL_S=$2
146+
break
147+
fi
148+
LAST_ERR="${p}: HTTP $1 $(head -c 120 /tmp/init.out | tr -d '"\n')"
149+
done
130150
fi
131151
[ -n "$PEER" ] && break
132-
[ $(( $(date +%s) - DISCOVER_START )) -ge 90 ] && fail discover "no provider advertises ${PROBE_SERVICE} after 90s"
133-
sleep 3
152+
[ $(( $(date +%s) - REACH_START )) -ge 120 ] && fail call "no provider of ${PROBE_SERVICE} answered initialize in 120s (${TRIED} attempts; last: ${LAST_ERR:-none discovered})"
153+
sleep 5
134154
done
135-
DISCOVER_S=$(( $(date +%s) - DISCOVER_START ))
155+
REACH_S=$(( $(date +%s) - REACH_START ))
136156
137-
# 4. And answers an MCP initialize through the mesh, end to end.
138-
# No trailing slash: the path maps onto the service's target_url
139-
# as-is. The body is JSON or an SSE frame; either names the server.
140-
set -- $(curl -s --unix-socket "$SOCK" -o /tmp/init.out -w '%{http_code} %{time_total}' \
141-
-X POST "http://localhost/sam/${PEER}/mcp/${PROBE_SERVICE}" \
142-
-H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
143-
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"sam-probe","version":"0"}}}')
144-
CALL_CODE=$1; CALL_S=$2
145-
[ "$CALL_CODE" = "200" ] || fail call "initialize on ${PEER} returned HTTP ${CALL_CODE}: $(head -c 200 /tmp/init.out)"
146-
grep -q '"serverInfo"' /tmp/init.out || fail call "initialize on ${PEER} returned no serverInfo: $(head -c 200 /tmp/init.out)"
147-
148-
printf '{"probe":"sam-cold-path","ok":true,"ready_s":%d,"router_latency_ms":%s,"connected_peers":%s,"discover_s":%d,"call_s":%s,"provider":"%s","elapsed_s":%d}\n' \
149-
"$READY_S" "${ROUTER_MS:-null}" "${PEERS:-null}" "$DISCOVER_S" "$CALL_S" "$PEER" "$(( $(date +%s) - START ))"
157+
printf '{"probe":"sam-cold-path","ok":true,"ready_s":%d,"router_latency_ms":%s,"connected_peers":%s,"reach_s":%d,"providers_tried":%d,"call_s":%s,"provider":"%s","elapsed_s":%d}\n' \
158+
"$READY_S" "${ROUTER_MS:-null}" "${PEERS:-null}" "$REACH_S" "$TRIED" "$CALL_S" "$PEER" "$(( $(date +%s) - START ))"
150159
volumes:
151160
- name: config-volume
152161
configMap:

.github/workflows/deploy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ jobs:
809809
810810
# `kubectl wait` can only wait for one condition; a failed Job would
811811
# otherwise sit out the whole timeout.
812-
for _ in $(seq 1 60); do
812+
for _ in $(seq 1 72); do
813813
status=$(kubectl get job "${JOB}" -n "${CANARY_NAMESPACE}" -o jsonpath='{range .status.conditions[*]}{.type}={.status}{"\n"}{end}')
814814
case "${status}" in
815815
*Complete=True*) break ;;

0 commit comments

Comments
 (0)