{"id":"6a3e9f39cabf74f3ccde4552","title":"2026 06 26 Issue 278","path":"how-to/committee/release-notes/2026-06-26-issue-278","contentMarkdown":"# 26-Jun-2026 — handle revoked Gmail tokens and coalesce push syncs [ref #278](https://github.com/nbarrett/ngx-ramblers/issues/278)\n\n## [build 721](https://github.com/nbarrett/ngx-ramblers/actions/runs/28248078096) — [commit e2670d1](https://github.com/nbarrett/ngx-ramblers/commit/e2670d108a844c4dfc47950c0500a361ce1ad3fb)\n\n_____\n\n## Revoked-token handling\n\nWhen a connected Gmail mailbox is revoked (the 7-day refresh-token expiry that happens while the Google Cloud OAuth consent screen is still in Testing), the Mail settings panel now:\n\n- Shows a warning on the connection card explaining the cause and linking straight to that project's OAuth Audience/publishing page, then prompts **Reconnect**.\n- Gains an always-visible link in the Google Cloud project step to check the publishing status (must be **In production**, not Testing).\n\nBoth links target the project derived from the OAuth client ID, so they resolve to the correct project per environment.\n\n## Push-sync concurrency guard\n\nThe Pub/Sub push handler fired `pollConnection` per push with no concurrency guard, so a burst of pushes (e.g. after a reconnect, or whenever a mailbox is busy) ran many full mailbox syncs at once - each holding decoded message bodies and attachment buffers in memory. On a 512MB machine this drove RSS into the OOM ceiling and saturated the single vCPU, tripping the health check and taking the site down.\n\nA per-connection single-flight guard (`syncConnectionCoalesced`) now runs at most one sync per mailbox at a time, and any pushes arriving during a sync collapse into a single trailing rerun so nothing is missed. The poll timer already had an equivalent guard; this brings the push path in line and keeps inbox work within the 512MB budget.\n\n## Alias derivation refactor and tests\n\nThe role-to-mailbox alias derivation is consolidated into a single pure function, deriveAliasesFrom, that both derivedAliases and derivedAliasesForConnection now delegate to, removing the duplicated role-alias mapping that existed in each. A new mocha spec (inbox-aliases.spec.ts) covers the derivation behaviours (single catch-all, custom forward email with case normalisation, multiple recipients resolving on the first, import-all general aliases, and unmatched roles) plus the message-to-role matching helpers, so regressions in inbox routing are caught.","contentHtml":"<h1>26-Jun-2026 — handle revoked Gmail tokens and coalesce push syncs <a href=\"https://github.com/nbarrett/ngx-ramblers/issues/278\">ref #278</a></h1>\n<h2><a href=\"https://github.com/nbarrett/ngx-ramblers/actions/runs/28248078096\">build 721</a> — <a href=\"https://github.com/nbarrett/ngx-ramblers/commit/e2670d108a844c4dfc47950c0500a361ce1ad3fb\">commit e2670d1</a></h2>\n<hr>\n<h2>Revoked-token handling</h2>\n<p>When a connected Gmail mailbox is revoked (the 7-day refresh-token expiry that happens while the Google Cloud OAuth consent screen is still in Testing), the Mail settings panel now:</p>\n<ul>\n<li>Shows a warning on the connection card explaining the cause and linking straight to that project&#39;s OAuth Audience/publishing page, then prompts <strong>Reconnect</strong>.</li>\n<li>Gains an always-visible link in the Google Cloud project step to check the publishing status (must be <strong>In production</strong>, not Testing).</li>\n</ul>\n<p>Both links target the project derived from the OAuth client ID, so they resolve to the correct project per environment.</p>\n<h2>Push-sync concurrency guard</h2>\n<p>The Pub/Sub push handler fired <code>pollConnection</code> per push with no concurrency guard, so a burst of pushes (e.g. after a reconnect, or whenever a mailbox is busy) ran many full mailbox syncs at once - each holding decoded message bodies and attachment buffers in memory. On a 512MB machine this drove RSS into the OOM ceiling and saturated the single vCPU, tripping the health check and taking the site down.</p>\n<p>A per-connection single-flight guard (<code>syncConnectionCoalesced</code>) now runs at most one sync per mailbox at a time, and any pushes arriving during a sync collapse into a single trailing rerun so nothing is missed. The poll timer already had an equivalent guard; this brings the push path in line and keeps inbox work within the 512MB budget.</p>\n<h2>Alias derivation refactor and tests</h2>\n<p>The role-to-mailbox alias derivation is consolidated into a single pure function, deriveAliasesFrom, that both derivedAliases and derivedAliasesForConnection now delegate to, removing the duplicated role-alias mapping that existed in each. A new mocha spec (inbox-aliases.spec.ts) covers the derivation behaviours (single catch-all, custom forward email with case normalisation, multiple recipients resolving on the first, import-all general aliases, and unmatched roles) plus the message-to-role matching helpers, so regressions in inbox routing are caught.</p>\n"}