Defer slow GitHub org sync to workflow queue for fast OAuth callback

Split syncGithubSessionFromToken into a fast path (initGithubSession:
exchange code, get viewer, store token+identity) and a slow path
(syncGithubOrganizations: list orgs/installations, sync workspaces).

completeAppGithubAuth now returns the 302 redirect in ~2s instead of
~18s by enqueuing the org sync to the workspace workflow queue
(fire-and-forget). This eliminates the proxy timeout window that was
causing duplicate callback requests.

bootstrapAppGithubSession (dev-only) still calls the full synchronous
sync since proxy timeouts are not a concern and it needs the session
fully populated before returning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nathan Flurry 2026-03-13 00:09:22 -07:00
parent a36431903e
commit fa4ed388d2
3 changed files with 108 additions and 34 deletions

View file

@ -62,7 +62,12 @@ interface RepoOverviewInput {
repoId: string;
}
const WORKSPACE_QUEUE_NAMES = ["workspace.command.addRepo", "workspace.command.createTask", "workspace.command.refreshProviderProfiles"] as const;
const WORKSPACE_QUEUE_NAMES = [
"workspace.command.addRepo",
"workspace.command.createTask",
"workspace.command.refreshProviderProfiles",
"workspace.command.syncGithubSession",
] as const;
const SANDBOX_AGENT_REPO = "rivet-dev/sandbox-agent";
type WorkspaceQueueName = (typeof WORKSPACE_QUEUE_NAMES)[number];
@ -366,6 +371,20 @@ export async function runWorkspaceWorkflow(ctx: any): Promise<void> {
refreshProviderProfilesMutation(loopCtx, msg.body as RefreshProviderProfilesCommand),
);
await msg.complete({ ok: true });
return Loop.continue(undefined);
}
if (msg.name === "workspace.command.syncGithubSession") {
await loopCtx.step({
name: "workspace-sync-github-session",
timeout: 60_000,
run: async () => {
const { syncGithubOrganizations } = await import("./app-shell.js");
await syncGithubOrganizations(loopCtx, msg.body as { sessionId: string; accessToken: string });
},
});
await msg.complete({ ok: true });
return Loop.continue(undefined);
}
return Loop.continue(undefined);