Fold a push's follow-up requests together #393

Closed
opened 2026-09-16 20:19:14 +00:00 by jcoffey-dev · 0 comments
Owner

Part of the high-latency work. Measured behind a proxy adding 125 ms each way (250 ms per round trip), by opening an unread message and following the mark-as-read echo.

A pushed mail change settles in two round trips instead of three.

  • Before: Mailbox/get + Email/changesEmail/get for what changed → the list, the open thread and a second Mailbox/get.
  • Now: Email/changes goes out with two Email/get calls, for updated and created messages, which back-reference /updated and /created. maxChanges is capped at maxObjectsInGet, so a page's back-referenced ids always fit in one get. The single Mailbox/get goes out at the same moment.
  • Then the list and the open thread follow, as before.
  • Updates merge only into messages already held. New mail is taken in, so the new-mail notice doesn't fetch it again.
  • cannotCalculateChanges is still caught: Email/changes is the first response, and chain throws on it.

Session refreshes.

  • A reply whose sessionState differs from the session's is announced once per new value, not once per reply.
  • useSession.refresh() shares a refresh already in flight.
  • In the mock, the session's state followed the data counter while replies always said "1". Every JMAP reply therefore triggered GET /api/auth/session?refresh=1. The session and its replies now share one constant, as they do on Stalwart. In the measurement, the per-request session calls are gone.

Tests.

  • Web: 1,363 pass, with 3 new cases:
    • one request for changes and their gets, with one Mailbox/get and nothing fetched twice;
    • cannotCalculateChanges;
    • a session state announced once.
  • Server: 251 pass.

No new UI strings.

Merged 2026-09-16 as coffey-labs/ihasmail@e158ebac5a

Rebuilt from: git history, session transcript.

Part of the high-latency work. Measured behind a proxy adding 125 ms each way (250 ms per round trip), by opening an unread message and following the mark-as-read echo. **A pushed mail change settles in two round trips instead of three.** - Before: `Mailbox/get` + `Email/changes` → `Email/get` for what changed → the list, the open thread and a second `Mailbox/get`. - Now: `Email/changes` goes out with two `Email/get` calls, for updated and created messages, which back-reference `/updated` and `/created`. `maxChanges` is capped at `maxObjectsInGet`, so a page's back-referenced ids always fit in one get. The single `Mailbox/get` goes out at the same moment. - Then the list and the open thread follow, as before. - Updates merge only into messages already held. New mail is taken in, so the new-mail notice doesn't fetch it again. - `cannotCalculateChanges` is still caught: `Email/changes` is the first response, and `chain` throws on it. **Session refreshes.** - A reply whose `sessionState` differs from the session's is announced once per new value, not once per reply. - `useSession.refresh()` shares a refresh already in flight. - In the mock, the session's `state` followed the data counter while replies always said `"1"`. Every JMAP reply therefore triggered `GET /api/auth/session?refresh=1`. The session and its replies now share one constant, as they do on Stalwart. In the measurement, the per-request session calls are gone. **Tests.** - Web: 1,363 pass, with 3 new cases: - one request for changes and their gets, with one `Mailbox/get` and nothing fetched twice; - `cannotCalculateChanges`; - a session state announced once. - Server: 251 pass. No new UI strings. **Merged** 2026-09-16 as coffey-labs/ihasmail@e158ebac5a92 <sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.