Each task's tests were run against a reference at its end state; the end states were replayed from master in order with the gate at each step (650 to 762 tests); each skeleton compiles against its tests and fails them. The reference is kept off this machine. Lessons T27 (every wait in a test has a limit) and T28 (mutate the reference before hand-over) come from this work. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4.7 KiB
M4a task 14: the serve loop
Branch: m4a (run git switch m4a; git status --short must be empty, otherwise stop)
Commit subject: gatewayd: serve, the event loop, typing, catch-up and reconnecting
Goal
The loop that ties tasks 03 to 13 together (spec sections 8 and 9):
- Connecting, at start and after every loss:
GET /users/me, open the WebSocket, wait forhello, then loggatewayd: connected to <url> as <username>. A connection that fails is tried again after 1, 2, 5, 10, then every 30 seconds, with one log line per attempt:gatewayd: cannot reach <url>: <error>; trying again in <n> s, then a newline andsee docs/runbook.md#mattermost-unreachable. A refused token (401 or 403) is never tried again:runreturnsStop::Auth. - After a restart (the first connection only): every turn left in flight gets
interrupted: gatewayd restarted before the answer arrived; ask againin its thread. A later reconnect must not do this: those turns are still running. - Catching up: the direct channel with each allowed user, and each allowed channel, from its mark. A channel without a mark is marked "now" and not caught up: history is not answered.
- Each post, live or caught up: posts in channels we do not track are not recorded at all. A tracked post is recorded as handled before it is acted on, so after a crash it is not answered twice (the in-flight record reports it instead). Then it is routed (task 11): a stranger is logged by user id and post id only, never with the text.
- Turns run on their own threads (task 13), recorded in flight while they run. When one ends, its session's waiting messages start the next.
- Typing: every
typing_every_ms,user_typingfor every thread with a turn running.
Files
- Copy:
crates/gatewayd/tests/serve.rs,crates/gatewayd/tests/serve_restart.rs,crates/gatewayd/tests/support/fake_mm.rs,crates/gatewayd/tests/support/gateway.rs, and the skeletonscrates/gatewayd/src/serve/mod.rsandcrates/gatewayd/src/serve/handle.rs - Modify:
crates/gatewayd/src/lib.rs(pub mod serve;),docs/implementer-log.md
The skeletons
serve/mod.rs, written: the pointers, INTERRUPTED, Log, Stop (Auth, State, Start,
Asked) and its Display, Tuning and its default, the Gateway struct, and the two functions
that are glue: run (the connect-or-back-off loop) and Gateway::event_loop (finish turns,
send typing, wait for an event, handle it). Read both first: they call everything you write.
To fill: From<StateError> for Stop, backoff, sleep_unless, connect, Gateway::new,
Gateway::connected.
serve/handle.rs, all to fill: now_ms, post, tracked, handle_post, start, finished,
typing, catch_up.
Each todo!() has its steps above it, with the exact log lines. run takes the token already
loaded and a stop flag, so the tests need no secrets and can end it; task 15's main passes a
flag that is never set.
Steps
- 1. Copy.
git switch m4a, thenmkdir -p crates/gatewayd/src/serve && cp docs/plans/M4a/files/crates/gatewayd/src/serve/mod.rs docs/plans/M4a/files/crates/gatewayd/src/serve/handle.rs crates/gatewayd/src/serve/,cp docs/plans/M4a/files/crates/gatewayd/tests/serve.rs docs/plans/M4a/files/crates/gatewayd/tests/serve_restart.rs crates/gatewayd/tests/andcp docs/plans/M4a/files/crates/gatewayd/tests/support/fake_mm.rs docs/plans/M4a/files/crates/gatewayd/tests/support/gateway.rs crates/gatewayd/tests/support/. Addpub mod serve;tolib.rs. - 2. See it fail.
cargo test -p gatewayd --no-fail-fast --test serve --test serve_restart. Expected: it compiles;serve6 fail;serve_restart6 fail and 1 passes (a damaged state file stopsrunbefore anything you write is called). - 3. Fill
mod.rsfirst (from,backoff,sleep_unless,Gateway::new,connect,connected), thenhandle.rs(now_ms,post,tracked,finished,typing,start,handle_post,catch_up).cargo check -p gatewaydafter each function. - 4. See it pass.
cargo test -p gatewayd --test serve --test serve_restart, five times. Expected: 6 and 7 passed each time, in about 2 s. - 5. Run the gate.
cargo fmt --all, thenmake gate. Expected last line:gate: ok. - 6. Log and commit.
git add crates/gatewayd docs/implementer-log.md Cargo.lock && git commit
Done when
- Both suites pass five times running;
make gateprintsgate: ok.
Stop and report if
- A test passes only sometimes, or a test takes 5 s or more (that is a wait that timed out, not a pass).
runorevent_loopseems to need a change. They are given; report instead.