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.
60 lines
1.5 KiB
Bash
Executable File
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"
|