Files
urus/scripts/hammer.sh
T
Claude ad19848db3 feat(ws+pubsub): on_open hook + ws_chat — v0.5 chunk 2
WsHandler::on_open(&mut self, sender) — defaulted, non-breaking,
added mid-chunk for veto-by-diff (the v0.3 "push" precedent for
defaults-level decisions): without it a listen-only ws client can
never be subscribed, since on_message never fires for a client that
doesn't send. Runs exactly once, first, in the conn actor, before any
buffered pipelined frame is decoded. Panic contract identical to
on_message: check_cancelled re-raise dance, else 1011 and no
on_close.

DISCOVERY 1 (documented, not fixed — inherent): the 101 reaches the
client BEFORE on_open runs, so "is my subscription live yet" is a
race client-side. App-level ack is the answer (any reply proves
on_open completed; callbacks are sequential). The integration tests
hit this immediately (first read of a join notice flaked into a 5s
read-timeout) and use a sync/synced ack; same reason Phoenix joins
reply.

DISCOVERY 2 (the structural one): PubSub::new() is in-runtime only,
but pipelines are built pre-runtime. crud's static-OnceLock bootstrap
DOES NOT COMPOSE with serve_with_shutdown here: a static pins the
table actor's last ServerRef forever, its inbox never closes, the
gen_server never exits, AllDone is unreachable — serve hangs (the
cross-thread-unpark limitation closes the workaround routes). The
pattern that works: NON-static Arc<OnceLock<PubSub<M>>> captured by
the route closure. Drain stops conns+listeners -> last Arc<Pipeline>
drops IN-runtime -> cell+handle drop -> inbox closes -> table exits.
Corollary: relays hold the Receiver only, NEVER a PubSub clone
(relay holds table's inbox open, table holds relay's receiver open:
mutual keepalive, shutdown hangs). Both rules in module docs, README,
and enforced by the new shutdown_with_open_chat_terminates test:
two open chat sockets + live relays + live table, shutdown must
return within 5s.

examples/ws_chat.rs: rooms as topics (room:{name}), on_open
subscribes (conn-actor pid: the monitor scopes cleanup to the
session) + spawns the relay (rx -> WsSender clone; exits on prune or
WsClosed), on_message broadcast_from(self_pid()) so the speaker is
never echoed, on_close broadcasts the leave notice and relies on the
monitor for unsubscribe.

Integration: ws_chat_broadcast_reaches_other_client_not_sender
(no-echo proven orderingly, no timeout reads: B speaks after A, A's
next frame must be B's) + shutdown_with_open_chat_terminates.

hammer.sh default subset now includes ws_ (v0.4 ran it ad hoc; ws IS
conn-lifecycle). Hammered: 35x subset (incl. both new tests) + 3x
full + 1x full under smarm-trace, all green. dbg!-grep clean. smarm
PRISTINE. README pub/sub + on_open sections; ROADMAP v0.5 as-landed.

Suite: 67 unit + 42 integration + 2 doc.
2026-06-12 10:30:08 +00:00

60 lines
1.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Flake hammer: the conn-lifecycle test discipline, in one command.
#
# Default (no args) = the full pre-commit ritual for conn-lifecycle changes:
# 1. N x the lifecycle-sensitive integration subset (fail-fast)
# 2. M x the full suite (unit + integration + doc)
#
# Usage:
# scripts/hammer.sh # 35x subset + 3x full
# scripts/hammer.sh -n 50 -f 5 # override counts
# scripts/hammer.sh -n 20 -f 0 -- shutdown sse # custom filter, skip full runs
#
# On failure: stops immediately, output of the failing run is in $LOG.
set -u
cd "$(dirname "$0")/.."
export PATH="$HOME/.cargo/bin:$PATH"
N=35
FULL=3
SUBSET=(shutdown timeout reaped slowloris streaming chunked sse stalled ws_)
while [[ $# -gt 0 ]]; do
case "$1" in
-n) N="$2"; shift 2 ;;
-f) FULL="$2"; shift 2 ;;
--) shift; SUBSET=("$@"); break ;;
*) echo "unknown arg: $1" >&2; exit 2 ;;
esac
done
LOG=target/hammer-fail.log
mkdir -p target
echo "== build once =="
cargo test --no-run --quiet || exit 1
fail() { # $1 = label
echo
echo "FAILED at $1 — output in $LOG"
exit 1
}
echo "== ${N}x subset: ${SUBSET[*]} =="
for ((i = 1; i <= N; i++)); do
printf '\r subset %d/%d ' "$i" "$N"
cargo test --quiet --test integration -- "${SUBSET[@]}" >"$LOG" 2>&1 \
|| fail "subset run $i/$N"
done
echo
echo "== ${FULL}x full suite =="
for ((i = 1; i <= FULL; i++)); do
printf ' full %d/%d\n' "$i" "$FULL"
cargo test --quiet >"$LOG" 2>&1 || fail "full run $i/$FULL"
done
rm -f "$LOG"
echo "hammer green: ${N}x subset + ${FULL}x full"