Commit 43d6c777 authored by edy's avatar edy

fix(desktop): keep bundle sync timeout non-fatal

parent a110b28a
......@@ -2163,6 +2163,7 @@ async function bootstrap(): Promise<void> {
configVersion: string | undefined,
action: RuntimeCloudFetchAction
) => {
const timeoutMessage = `Project bundle sync timed out after ${Math.round(PROJECT_BUNDLE_BOOTSTRAP_TIMEOUT_MS / 1000)}s.`;
console.info("[bundle-bootstrap]", "bundle.sync.start", {
action,
configVersion,
......@@ -2174,7 +2175,7 @@ async function bootstrap(): Promise<void> {
await withTimeout(
projectBundleService.syncRemoteBundles(skills, configVersion, action),
PROJECT_BUNDLE_BOOTSTRAP_TIMEOUT_MS,
`Project bundle sync timed out after ${Math.round(PROJECT_BUNDLE_BOOTSTRAP_TIMEOUT_MS / 1000)}s.`
timeoutMessage
);
console.info("[bundle-bootstrap]", "bundle.sync.done", {
action,
......@@ -2185,13 +2186,24 @@ async function bootstrap(): Promise<void> {
} catch (error) {
const rawMessage = error instanceof Error ? (error.stack ?? error.message) : String(error);
const userMessage = error instanceof Error ? error.message : String(error);
projectBundleService.setSyncError(userMessage);
console.error("[bundle-bootstrap]", "bundle.sync.error", {
const timedOut = userMessage === timeoutMessage;
if (!timedOut) {
projectBundleService.setSyncError(userMessage);
}
const logContext = {
action,
configVersion,
skillIds: skills.map((skill) => skill.skillId),
error: rawMessage,
timedOut: userMessage.includes("timed out")
timedOut
};
if (timedOut) {
console.warn("[bundle-bootstrap]", "bundle.sync.timeout", logContext);
await traceBootstrap("project-bundle-sync:" + action + ":timeout:" + rawMessage.replace(/\r?\n/g, " | "));
return;
}
console.error("[bundle-bootstrap]", "bundle.sync.error", {
...logContext
});
await traceBootstrap("project-bundle-sync:" + action + ":error:" + rawMessage.replace(/\r?\n/g, " | "));
}
......
......@@ -1170,10 +1170,13 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
runtimeStatus,
gatewayStatus
});
const hasUsableProjectInventory = projects.some((project) => project.ready)
|| Boolean(currentProject?.isBuiltinHome && currentProject.ready);
const shouldWaitForProjectSync = config.apiKeyConfigured
&& config.setupMode === "employee-key"
&& runtimeCloudStatus.state === "ready"
&& bundleSyncStatus.state === "syncing"
&& !hasUsableProjectInventory
&& baseChatSummary.chatLaunchState !== "error";
if (shouldWaitForProjectSync && baseChatSummary.startupPhase !== "syncing-projects") {
void startupLogger.warn("workspace-summary", "phase.override", "Project sync phase is overriding the base startup phase because no project inventory is available yet.", {
......@@ -1181,6 +1184,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
basePhase: baseChatSummary.startupPhase,
runtimeCloudState: runtimeCloudStatus.state,
projectCount: projects.length,
hasUsableProjectInventory,
bundleSyncState: bundleSyncStatus.state
});
}
......
......@@ -289,6 +289,15 @@ export class ProjectBundleService {
};
}
private setSyncFailure(error: unknown): void {
const message = error instanceof Error ? error.message : String(error);
this.syncStatus = {
...this.syncStatus,
state: "error",
lastError: message
};
}
async syncRemoteBundles(remoteSkills: RemoteSkillAsset[], configVersion?: string, _action?: RuntimeCloudFetchAction): Promise<void> {
const runSync = async (): Promise<void> => {
const startedAt = Date.now();
......@@ -376,7 +385,24 @@ export class ProjectBundleService {
});
};
const nextRun = this.syncTail.then(runSync);
const nextRun = this.syncTail.then(async () => {
try {
await runSync();
} catch (error) {
this.setSyncFailure(error);
logBundle("bundle.sync.error", {
action: _action ?? "unknown",
configVersion,
error: error instanceof Error ? error.message : String(error)
});
await this.startupLogger?.error("project-bundle", "sync.error", "Project bundle sync failed.", {
action: _action ?? "unknown",
configVersion,
error: error instanceof Error ? (error.stack ?? error.message) : String(error)
});
throw error;
}
});
this.syncTail = nextRun.catch(() => undefined);
await nextRun;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment