Repository navigation
fix(app): keep the Office worker queue moving and bound What's New - #62000
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
There was a problem hiding this comment.
The change looks sound. I reproduced the Office worker queue bug on the base by running the new worker-rpc.test.ts case there: a reply that cannot be cloned throws DataCloneError out of the handler's .then, which takes down the worker in Bun and would hang the queue in a browser. With this PR the caller rejects, the bitmaps are closed and the next call runs. All worker-rpc* and whats-new-machine tests pass (29), and tsc -b for gui-plugins is clean. What's New needs the desktop app, so I checked it only through the machine tests and by reading the code. The Settings watcher only dispatches disabled when release notes are turned off, and the timeout and dispose paths both abort the changelog fetch.
Public API: unchanged. AbortedError and the onCrash option are internal to gui-plugins, and AbortedError extends WorkerClosedError, so existing instanceof checks keep working.
No blocking concerns.
There was a problem hiding this comment.
The new push rebases and squashes the same change onto newer dev. The patch is unchanged apart from one line of context in renderer.tsx that comes from dev. I re-ran the worker-rpc* and whats-new-machine tests (29 pass), and tsc -b for gui-plugins is clean.
Public API: unchanged.
No new concerns.
Moves two low-severity lifecycles in
gui-pluginsinto explicit state machines: the Office worker RPC queue (microsoft-office/worker-rpc-machine.ts) and post-update What's New (updater/whats-new-machine.ts).Bugs
Office worker RPC (
worker-rpc.ts)self.postMessagecannot clone (a detached buffer or an uncloneable value) threw inside.then(onFulfilled). That skippedrunning = false, so the caller never settled and every later call on the worker hung.current: an unknown method, or a finished call, stayed instate.currentacross the next macrotask yield.WorkerClosedError, the same class as a dead worker.abortlisteners, so a later abort posted{ cancel }to a terminated worker.postMessagethrow left the call inpendingforever.office-worker.tsadded duplicateerror/messageerrorlisteners and aborted its controller before it closed the client.What's New (
renderer.tsx,whats-new.tsx,beta-dialog.tsx)fetchhad no timeout and the chunkimport()calls had no.catch. A stalled request could resolve minutes later and open with{ replace: true }, which closed every open dialog.timersset before it marked the release seen, but beta marked it at once. The host'swhenMountedgate already covers what the timer did.Machines
stateDiagram-v2 direction LR state "worker queue" as S { idle --> yielding: request (schedule-turn) yielding --> running: turn.ready [attempt] yielding --> idle: cancel empties queue running --> running: cancel (abort-handler) / keyed replace in queue running --> yielding: handler settles, queue non-empty running --> idle: handler settles, queue empty }loading+ eventloadedwith contentabort-load,mark-seen,openloadedempty,disabledabort-load,mark-seenload.failed,load.timed-out(15 s),disposedabort-loaddonePromise.try(...).catch(...). A failedpost-requestbecomescall.post-failed, and a failedokreply becomesreply.failed, which closes its bitmaps and posts an error reply so the caller settles. A finished call always leavesrunningin the same transition.turn.readyandhandler.*carry the attempt, and a stale one only closes its bitmaps.Deleted
ClientState { next, failure },ServerState { running, current }, and the mutablequeueandpendingmaps (the driver keeps only the callback map and the controllers).error/messageerrorlisteners inoffice-worker.ts.showWhatsNew/showBetaNotes, thetimersset, the 500 ms delay, and the scatteredctx.signal.abortedchecks. These are now split intoloadWhatsNewHighlights/openWhatsNewandreadBetaNotes/openBetaNotes.Deviations from the design
loading | done.shown,settled,failedanddisposedshowed nothing different. Channel results merged into oneloadedevent with aWhatsNewContentunion.issuedfield: dropped, becauseattemptalone fences timers. Nocancel-turneffect either: a staleturn.readyis a no-op.AbortedErrorsubclassesWorkerClosedError: current callers inspreadsheet.tsxandpresentation.tsxkeep ignoring aborts without edits. Those files belong to batch L38, so this PR leaves them alone.Product calls
{ replace: true }removed).Off the hot path: no benchmark.
Visual