From 5f6e7718bd84d435cc91fd632f02cf547fba17dc Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Tue, 19 Nov 2024 09:05:43 -0700 Subject: [PATCH] not running debounced updates while network requests in flight --- nextjs/src/app/api/trpc/[trpc]/route.ts | 2 ++ .../[assignmentName]/EditAssignment.tsx | 10 ++++++++-- .../[moduleName]/page/[pageName]/EditPage.tsx | 8 +++++++- .../[moduleName]/quiz/[quizName]/EditQuiz.tsx | 11 +++++++---- .../utils/useAuthoritativeUpdates.tsx | 17 ++++++++++++++--- .../assignmentsFileStorageService.ts | 2 ++ 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/nextjs/src/app/api/trpc/[trpc]/route.ts b/nextjs/src/app/api/trpc/[trpc]/route.ts index 84c8004..90a1044 100644 --- a/nextjs/src/app/api/trpc/[trpc]/route.ts +++ b/nextjs/src/app/api/trpc/[trpc]/route.ts @@ -3,6 +3,8 @@ import { trpcAppRouter } from "@/services/serverFunctions/router/app"; import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; const handler = async (request: Request) => { + + await new Promise(r => setTimeout(r, 1000)); // delay for testing return fetchRequestHandler({ endpoint: "/api/trpc", req: request, diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx index fb6af7d..c8cfbda 100644 --- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx +++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx @@ -31,7 +31,7 @@ export default function EditAssignment({ const router = useRouter(); const { courseName } = useCourseContext(); const [settings] = useLocalCourseSettingsQuery(); - const [assignment, { dataUpdatedAt: serverDataUpdatedAt }] = + const [assignment, { dataUpdatedAt: serverDataUpdatedAt, isFetching: assignmentIsFetching }] = useAssignmentQuery(moduleName, assignmentName); const updateAssignment = useUpdateAssignmentMutation(); @@ -55,6 +55,11 @@ export default function EditAssignment({ const handler = setTimeout(() => { try { + if (assignmentIsFetching || updateAssignment.isPending) { + console.log("network requests in progress, not updating assignments"); + return; + } + const updatedAssignment: LocalAssignment = localAssignmentMarkdown.parseMarkdown(text); if ( @@ -62,7 +67,7 @@ export default function EditAssignment({ localAssignmentMarkdown.toMarkdown(updatedAssignment) ) { if (clientIsAuthoritative) { - console.log("updating assignment"); + console.log("updating assignment, client is authoritative"); updateAssignment .mutateAsync({ assignment: updatedAssignment, @@ -109,6 +114,7 @@ export default function EditAssignment({ clientDataUpdatedAt, clientIsAuthoritative, courseName, + assignmentIsFetching, moduleName, router, serverUpdatedAt, diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/EditPage.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/EditPage.tsx index c6df51b..172fb58 100644 --- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/EditPage.tsx +++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/EditPage.tsx @@ -24,7 +24,7 @@ export default function EditPage({ }) { const router = useRouter(); const { courseName } = useCourseContext(); - const [page, { dataUpdatedAt }] = usePageQuery( + const [page, { dataUpdatedAt, isFetching }] = usePageQuery( moduleName, pageName ); @@ -42,6 +42,11 @@ export default function EditPage({ useEffect(() => { const delay = 500; const handler = setTimeout(() => { + if (isFetching || updatePage.isPending) { + console.log("network requests in progress, not updating page"); + return; + } + try { const updatedPage = localPageMarkdownUtils.parseMarkdown(text); if ( @@ -89,6 +94,7 @@ export default function EditPage({ }, [ clientIsAuthoritative, courseName, + isFetching, moduleName, page, pageName, diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx index 46bda51..032ca6f 100644 --- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx +++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx @@ -65,10 +65,8 @@ export default function EditQuiz({ }) { const router = useRouter(); const { courseName } = useCourseContext(); - const [quiz, { dataUpdatedAt: serverDataUpdatedAt }] = useQuizQuery( - moduleName, - quizName - ); + const [quiz, { dataUpdatedAt: serverDataUpdatedAt, isFetching }] = + useQuizQuery(moduleName, quizName); const updateQuizMutation = useUpdateQuizMutation(); const { clientIsAuthoritative, text, textUpdate, monacoKey } = useAuthoritativeUpdates({ @@ -82,6 +80,10 @@ export default function EditQuiz({ useEffect(() => { const delay = 1000; const handler = setTimeout(async () => { + if (isFetching || updateQuizMutation.isPending) { + console.log("network requests in progress, not updating page"); + return; + } try { if ( quizMarkdownUtils.toMarkdown(quiz) !== @@ -128,6 +130,7 @@ export default function EditQuiz({ }, [ clientIsAuthoritative, courseName, + isFetching, moduleName, quiz, quizName, diff --git a/nextjs/src/app/course/[courseName]/utils/useAuthoritativeUpdates.tsx b/nextjs/src/app/course/[courseName]/utils/useAuthoritativeUpdates.tsx index 5895e73..db6d10e 100644 --- a/nextjs/src/app/course/[courseName]/utils/useAuthoritativeUpdates.tsx +++ b/nextjs/src/app/course/[courseName]/utils/useAuthoritativeUpdates.tsx @@ -12,8 +12,12 @@ export function useAuthoritativeUpdates({ const [clientDataUpdatedAt, setClientDataUpdatedAt] = useState(serverUpdatedAt); const [updateMonacoKey, setUpdateMonacoKey] = useState(1); + const clientIsAuthoritative = useMemo(() => { + const authority = serverUpdatedAt <= clientDataUpdatedAt + 500; + console.log("client is authoritative", authority); + return authority; + }, [clientDataUpdatedAt, serverUpdatedAt]); // if it is close, it might be the second-to-last update changing the first (by file update delays), add some buffer... - // console.log("client is authoritative", clientIsAuthoritative); const textUpdate = useCallback((t: string, updateMonaco: boolean = false) => { setText(t); setClientDataUpdatedAt(Date.now()); @@ -22,13 +26,20 @@ export function useAuthoritativeUpdates({ return useMemo( () => ({ - clientIsAuthoritative: serverUpdatedAt <= clientDataUpdatedAt, + clientIsAuthoritative, serverUpdatedAt, clientDataUpdatedAt, textUpdate, text, monacoKey: updateMonacoKey, }), - [clientDataUpdatedAt, serverUpdatedAt, text, textUpdate, updateMonacoKey] + [ + clientDataUpdatedAt, + clientIsAuthoritative, + serverUpdatedAt, + text, + textUpdate, + updateMonacoKey, + ] ); } diff --git a/nextjs/src/services/fileStorage/assignmentsFileStorageService.ts b/nextjs/src/services/fileStorage/assignmentsFileStorageService.ts index cf39560..2bca34e 100644 --- a/nextjs/src/services/fileStorage/assignmentsFileStorageService.ts +++ b/nextjs/src/services/fileStorage/assignmentsFileStorageService.ts @@ -71,6 +71,8 @@ export const assignmentsFileStorageService = { const assignmentMarkdown = assignmentMarkdownSerializer.toMarkdown(assignment); console.log(`Saving assignment ${filePath}`); + + await fs.writeFile(filePath, assignmentMarkdown); }, async delete({