mirror of
https://github.com/willchen96/mike.git
synced 2026-07-24 23:41:04 +02:00
fix: batch directory-modal project fetch instead of N+1 getProject burst
Every directory picker (AddDocumentsModal, UseWorkflowModal, the assistant
project selector) loads its "Projects" tab through useDirectoryData, which
fired one GET /projects/:id for EVERY existing project the moment the modal
opened. Each of those requests costs an auth verification against GoTrue
plus ~6 PostgREST queries, so an account with N projects produced an
~8xN-request burst on the Supabase gateway per modal open.
Under that burst the gateway genuinely falls over: measured locally against
the Supabase CLI stack, overlapping modal-open storms drove GoTrue into
Postgres connection exhaustion ("failed to connect ... context deadline
exceeded") and produced 467x 500 + 641x 504 on /auth/v1/user in a single
run — surfacing to users as failed project creates/loads, and to the e2e
suite as the intermittent Kong 502s its specs currently retry around.
Fix: GET /projects now accepts ?include=documents and returns each
project's documents from one batched query (same attach helpers as
GET /projects/:id, run once across all documents), and useDirectoryData
uses it. A modal open is now 1 API request and a fixed number of DB
queries regardless of project count. After the change the same storm
harness produced zero 5xx and zero auth failures.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
0843e2909a
commit
36cddb2566
3 changed files with 58 additions and 17 deletions
|
|
@ -1,11 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
getLibrary,
|
||||
getProject,
|
||||
listProjects,
|
||||
} from "@/app/lib/mikeApi";
|
||||
import { getLibrary, listProjects } from "@/app/lib/mikeApi";
|
||||
import type { Document, LibraryFolder, Project } from "./types";
|
||||
|
||||
export type DirectoryTab = "files" | "templates" | "projects";
|
||||
|
|
@ -45,17 +41,14 @@ async function loadTemplates() {
|
|||
}
|
||||
|
||||
async function loadProjects() {
|
||||
const projects = await listProjects();
|
||||
const fullProjects = await Promise.all(
|
||||
projects.map((project) => getProject(project.id)),
|
||||
);
|
||||
const projectCounts = new Map(
|
||||
projects.map((project) => [project.id, project.document_count ?? 0]),
|
||||
);
|
||||
return fullProjects.map((project) => ({
|
||||
// One batched request. Fanning out getProject(id) per project caused an
|
||||
// N+1 burst on every directory-modal open that could overwhelm the
|
||||
// Supabase gateway once an account had accumulated projects.
|
||||
const projects = await listProjects({ includeDocuments: true });
|
||||
return projects.map((project) => ({
|
||||
...project,
|
||||
document_count:
|
||||
project.documents?.length ?? projectCounts.get(project.id) ?? 0,
|
||||
project.documents?.length ?? project.document_count ?? 0,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,8 +163,11 @@ async function toApiError(response: Response, path: string) {
|
|||
// Projects
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export async function listProjects(): Promise<Project[]> {
|
||||
return apiRequest<Project[]>("/projects");
|
||||
export async function listProjects(options?: {
|
||||
includeDocuments?: boolean;
|
||||
}): Promise<Project[]> {
|
||||
const query = options?.includeDocuments ? "?include=documents" : "";
|
||||
return apiRequest<Project[]>(`/projects${query}`);
|
||||
}
|
||||
|
||||
export async function createProject(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue