WIP: merge queue: checking main (4c3937e) and #470 together #475

Closed
mergify[bot] wants to merge 2 commits from mergify/merge-queue/9781139bcc into main
2 Commits
Author SHA1 Message Date
mergify[bot] 0d20d599ba Merge of #470 2026-07-09 01:35:44 +00:00
JMR-dev c5144ebe03 perf(outlook): respect Microsoft Graph throttling with batching & chunked upload
Add a throttle-aware Microsoft Graph HTTP layer (org.libremail.mail.graph) and route
the live me/sendMail path through it, composing with #360's AccountThrottleGate:

- GraphHttpClient: the single Graph HTTP transport seam; preserves the send path's
  may-have-sent distinction (GraphTransportException) and parses Retry-After.
- GraphThrottle: caps Graph concurrency at 4, honors a 429/503 Retry-After via the
  shared per-account backoff gate (retry after the honored wait, bounded), clears it
  on a 2xx. Because the gate is shared+account-keyed, a Graph 429 also cools that
  account's IMAP background work down.
- GraphBatch: multiplexes ops via $batch (<=20/call), collapsing N calls to
  ceil(N/20); feeds per-op 429s back into the gate.
- GraphUploadSession: createUploadSession + chunked Content-Range PUTs for content
  over Graph's ~4 MB one-shot ceiling (320 KiB-multiple chunks).
- GraphSender.send now honors a Graph 429 once (Retry-After) before falling back to
  SMTP, instead of failing over on the first throttle.

Outlook mail is read over IMAP and the Graph token is Mail.Send-scoped, so $batch
reads and draft-based chunked attachment upload have no live call site yet (they need
the Mail.ReadWrite scope, a re-consent-forcing change kept out of this perf ticket);
both ship as fully-tested capabilities of the Graph layer.

Unit tests (MockK the HTTP client, coroutines-test virtual time, no real sleeps) cover
429+Retry-After backoff, $batch call-count reduction, and chunked upload; an
instrumented test exercises the toolkit under the Android runtime. PII-free AppLog
(accountLogRef) throughout; SPDX on every file.

Closes #364
2026-07-08 19:26:32 -05:00