-
Notifications
You must be signed in to change notification settings - Fork 445
fix(desktop): stop polling unavailable collaboration authority #4527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
60e1a11
25dcf3d
092019a
1317554
0c5adb4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ | |
|
|
||
| import { RuntimeHostOperationError } from '@maka/runtime-host/client'; | ||
| import type { DesktopRuntimeHostClient } from './runtime-host-client.js'; | ||
| import type { CollaborationTurnRequestQueryResult } from '@maka/runtime-host/protocol'; | ||
| import { | ||
| encodeDesktopCollaborationInvitation, | ||
| type DesktopCollaborationConnectionTarget, | ||
|
|
@@ -101,7 +102,11 @@ export function registerRuntimeHostCollaborationIpc( | |
| return await client.queryCollaborationTurnRequests(requestedSessionId); | ||
| } catch (error) { | ||
| if (requestedSessionId === undefined && isCollaborationInboxUnavailable(error)) { | ||
| return { canRequestTurns: false, requests: [] }; | ||
| return { | ||
| canRequestTurns: false, | ||
| requests: [], | ||
| authorityUnavailable: true, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: |
||
| } satisfies CollaborationTurnRequestQueryResult & { authorityUnavailable: true }; | ||
| } | ||
| throw error; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,6 +107,7 @@ export interface RuntimeHostDesktopTargetSnapshot { | |
| readonly target: ResolvedRuntimeHostProfile; | ||
| readonly readiness: 'ready' | 'reconnecting'; | ||
| readonly candidate?: DesktopRuntimeHostCandidate; | ||
| readonly collaborationAuthority?: boolean; | ||
| } | ||
|
|
||
| export type RuntimeHostDesktopTargetState = | ||
|
|
@@ -115,18 +116,21 @@ export type RuntimeHostDesktopTargetState = | |
| readonly target: ResolvedRuntimeHostProfile; | ||
| readonly readiness: 'connecting' | 'reconnecting'; | ||
| readonly hostId?: string; | ||
| readonly collaborationAuthority?: boolean; | ||
| } | ||
| | { | ||
| readonly epoch: string; | ||
| readonly target: ResolvedRuntimeHostProfile; | ||
| readonly readiness: 'ready'; | ||
| readonly candidate: DesktopRuntimeHostCandidate; | ||
| readonly collaborationAuthority?: boolean; | ||
| } | ||
| | { | ||
| readonly epoch: string; | ||
| readonly target: ResolvedRuntimeHostProfile; | ||
| readonly readiness: 'unavailable'; | ||
| readonly hostId?: string; | ||
| readonly collaborationAuthority?: boolean; | ||
| readonly error: Error; | ||
| }; | ||
|
|
||
|
|
@@ -218,6 +222,7 @@ interface DesktopRuntimeHostTargetGeneration { | |
| readonly observations: RuntimeHostSessionObservationRegistry; | ||
| state: RuntimeHostDesktopTargetState; | ||
| hostId?: string; | ||
| collaborationAuthority?: boolean; | ||
| lifecycle?: RuntimeHostReconnectLifecycle<DesktopRuntimeHostCandidate>; | ||
| unsubscribeLifecycle?: () => void; | ||
| unsubscribeRoutes?: () => void; | ||
|
|
@@ -475,12 +480,20 @@ class RuntimeHostDesktopManagerImpl implements RuntimeHostDesktopManager { | |
| ...(target.hostId ? { hostId: target.hostId } : {}), | ||
| target: target.target, | ||
| readiness: candidate ? 'ready' : 'reconnecting', | ||
| ...(target.collaborationAuthority === undefined | ||
| ? {} | ||
| : { collaborationAuthority: target.collaborationAuthority }), | ||
| ...(candidate ? { candidate } : {}), | ||
| }; | ||
| } | ||
|
|
||
| entries(): readonly RuntimeHostDesktopTargetState[] { | ||
| return [...this.#targets.values()].map((target) => target.state); | ||
| return [...this.#targets.values()].map((target) => ({ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: this spreads the generation's |
||
| ...target.state, | ||
| ...(target.collaborationAuthority === undefined | ||
| ? {} | ||
| : { collaborationAuthority: target.collaborationAuthority }), | ||
| })); | ||
| } | ||
|
|
||
| ownsScope(scope: { readonly hostId: string; readonly targetEpoch: string }): boolean { | ||
|
|
@@ -1081,6 +1094,12 @@ class RuntimeHostDesktopManagerImpl implements RuntimeHostDesktopManager { | |
| // replay one-shot join progress. | ||
| onConnectionPhase: (phase) => onConnectionPhase?.(phase), | ||
| ...(refreshPeerRoutes ? {} : { refreshPeerRoutes: false }), | ||
| onHostStatus: (status) => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: this overrides That has a side effect the PR does not mention: Resolve this together with the ready-path probe below. Either keep a main-process memo and register no observer at all, or keep the observer, register it only while the capability is unknown, and drop the explicit probe. |
||
| if (status.collaborationAuthority !== undefined) { | ||
| target.collaborationAuthority = status.collaborationAuthority; | ||
| } | ||
| target.input.onHostStatus?.(status); | ||
| }, | ||
| signal, | ||
| ...(takeoverHostEpoch === undefined ? {} : { takeoverHostEpoch }), | ||
| }, | ||
|
|
@@ -1093,6 +1112,13 @@ class RuntimeHostDesktopManagerImpl implements RuntimeHostDesktopManager { | |
| throw error; | ||
| } | ||
| if (result.kind === 'ready') { | ||
| const status = result.candidate.client.status; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: this awaits an extra It also looks redundant. The connect path already performs a P3 on line 1006: |
||
| if (typeof status === 'function') { | ||
| const observed = await status.call(result.candidate.client, 5_000).catch(() => undefined); | ||
| if (observed?.collaborationAuthority !== undefined) { | ||
| target.collaborationAuthority = observed.collaborationAuthority; | ||
| } | ||
| } | ||
| target.hostId = result.candidate.client.hostId; | ||
| const previous = target.lastCandidate; | ||
| const retainedOwnedProcess = | ||
|
|
@@ -1311,12 +1337,18 @@ class RuntimeHostDesktopManagerImpl implements RuntimeHostDesktopManager { | |
| target: target.target, | ||
| readiness: 'ready', | ||
| candidate, | ||
| ...(target.collaborationAuthority === undefined | ||
| ? {} | ||
| : { collaborationAuthority: target.collaborationAuthority }), | ||
| } | ||
| : { | ||
| epoch: target.epoch, | ||
| target: target.target, | ||
| readiness: 'reconnecting', | ||
| ...(target.hostId ? { hostId: target.hostId } : {}), | ||
| ...(target.collaborationAuthority === undefined | ||
| ? {} | ||
| : { collaborationAuthority: target.collaborationAuthority }), | ||
| }, | ||
| ); | ||
| }); | ||
|
|
@@ -1329,12 +1361,18 @@ class RuntimeHostDesktopManagerImpl implements RuntimeHostDesktopManager { | |
| target: target.target, | ||
| readiness: 'ready', | ||
| candidate, | ||
| ...(target.collaborationAuthority === undefined | ||
| ? {} | ||
| : { collaborationAuthority: target.collaborationAuthority }), | ||
| } | ||
| : { | ||
| epoch: target.epoch, | ||
| target: target.target, | ||
| readiness: 'reconnecting', | ||
| ...(target.hostId ? { hostId: target.hostId } : {}), | ||
| ...(target.collaborationAuthority === undefined | ||
| ? {} | ||
| : { collaborationAuthority: target.collaborationAuthority }), | ||
| }, | ||
| ); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: this does not cross the boundary @Phoenix500526 asked about. The cache here is a local
authorityvariable and a local mark closure, notruntimeHostMetadataandmarkRuntimeHostCollaborationUnavailable. Replace the callback passed atpreload.ts:1418with a no-op, or have it write the wrong scope key, and this test still passes, which is exactly the failure mode the request was meant to rule out.Assert against the real pair instead: mark through
markRuntimeHostCollaborationUnavailable, then read back throughruntimeHostMetadataForon the second poll.