From 85bc401e471454c82c43093926ae2ba16fa93088 Mon Sep 17 00:00:00 2001 From: Outvi V Date: Sat, 31 May 2025 00:40:13 +0800 Subject: [PATCH 01/14] feat(page.note): add delay and retry to embedded note loading --- .../src/components/page/page.note.vue | 49 +++++++++++++++++-- .../frontend/src/components/page/page.vue | 2 +- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/page/page.note.vue b/packages/frontend/src/components/page/page.note.vue index df26874c17..98f72f0d9d 100644 --- a/packages/frontend/src/components/page/page.note.vue +++ b/packages/frontend/src/components/page/page.note.vue @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/page/page.vue b/packages/frontend/src/components/page/page.vue index a31c5eff28..9f9feeed49 100644 --- a/packages/frontend/src/components/page/page.vue +++ b/packages/frontend/src/components/page/page.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only From 5e6c6fccc482283bfd0fc369557ffab6cf8617bd Mon Sep 17 00:00:00 2001 From: Outvi V Date: Sat, 31 May 2025 10:09:46 +0800 Subject: [PATCH 02/14] chore: lint --- .../src/components/page/page.note.vue | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/frontend/src/components/page/page.note.vue b/packages/frontend/src/components/page/page.note.vue index 98f72f0d9d..f459a437d2 100644 --- a/packages/frontend/src/components/page/page.note.vue +++ b/packages/frontend/src/components/page/page.note.vue @@ -25,52 +25,54 @@ const props = defineProps<{ const note = ref(null); -let timeoutId = null; +// eslint-disable-next-line id-denylist +let timeoutId: ReturnType | null = null; async function sleep(ms: number): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve() + return new Promise((resolve) => { + window.setTimeout(() => { + resolve(); }, ms); }); } -async function retryOnThrottle(f: ()=>Promise, retryCount: number = 5): Promise { - let lastResult: T = undefined!; - const r = Math.random(); - for(let i=0; i(f: ()=>Promise, retryCount = 5): Promise { + let lastResult: T; + for (let i = 0; i < retryCount; i++) { const [ok, resultOrError] = await f() .then(result => [true, result]) .catch(err => [false, err]); - - lastResult = resultOrError; + + lastResult = resultOrError; if (ok) { break; } // RATE_LIMIT_EXCEEDED - if (resultOrError?.id === "d5826d14-3982-4d2e-8011-b9e9f02499ef") { + if (resultOrError?.id === 'd5826d14-3982-4d2e-8011-b9e9f02499ef') { await sleep(resultOrError?.info?.fullResetMs ?? 1000); continue; } throw resultOrError; } - return lastResult; + return lastResult; } onMounted(() => { if (props.block.note == null) return; - timeoutId = setTimeout(() => { + timeoutId = window.setTimeout(() => { retryOnThrottle(() => misskeyApi('notes/show', { noteId: props.block.note })).then(result => { - note.value = result; + note.value = result; }); }, 500 * props.index); // rate limit is 2 reqs per sec }); onUnmounted(() => { - if (timeoutId !== null) clearTimeout(timeoutId); + if (timeoutId !== null) { + window.clearTimeout(timeoutId); + } }); From e36ea27517c43352fe3173f54e558ad549388f0e Mon Sep 17 00:00:00 2001 From: Outvi V Date: Sat, 31 May 2025 22:50:21 +0800 Subject: [PATCH 03/14] fix(page.note): throw (not return) on all attempts throttled --- .../frontend/src/components/page/page.note.vue | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/page/page.note.vue b/packages/frontend/src/components/page/page.note.vue index f459a437d2..cc1075d42a 100644 --- a/packages/frontend/src/components/page/page.note.vue +++ b/packages/frontend/src/components/page/page.note.vue @@ -37,13 +37,15 @@ async function sleep(ms: number): Promise { } async function retryOnThrottle(f: ()=>Promise, retryCount = 5): Promise { - let lastResult: T; + let lastOk: boolean; + let lastResultOrError: T; for (let i = 0; i < retryCount; i++) { const [ok, resultOrError] = await f() .then(result => [true, result]) .catch(err => [false, err]); - lastResult = resultOrError; + lastOk = ok; + lastResultOrError = resultOrError; if (ok) { break; @@ -55,9 +57,16 @@ async function retryOnThrottle(f: ()=>Promise, retryCount = 5): Promise continue; } + // Throw for non-throttling errors throw resultOrError; } - return lastResult; + + if (lastOk) { + return lastResultOrError; + } else { + // Give up after getting throttled too many times + throw lastResultOrError; + } } onMounted(() => { From de7f7984cdd0255e6f84414b0861d547511248a4 Mon Sep 17 00:00:00 2001 From: Outvi V Date: Sun, 1 Jun 2025 06:30:28 +0800 Subject: [PATCH 04/14] chore: move `retryOnThrottled` to frontend-shared --- .../frontend-shared/js/retry-on-throttled.ts | 40 +++++++++++++++++ .../src/components/page/page.note.vue | 44 +------------------ 2 files changed, 42 insertions(+), 42 deletions(-) create mode 100644 packages/frontend-shared/js/retry-on-throttled.ts diff --git a/packages/frontend-shared/js/retry-on-throttled.ts b/packages/frontend-shared/js/retry-on-throttled.ts new file mode 100644 index 0000000000..4234a18b51 --- /dev/null +++ b/packages/frontend-shared/js/retry-on-throttled.ts @@ -0,0 +1,40 @@ +async function sleep(ms: number): Promise { + return new Promise((resolve) => { + window.setTimeout(() => { + resolve(); + }, ms); + }); +} + +export async function retryOnThrottled(f: ()=>Promise, retryCount = 5): Promise { + let lastOk = false; + let lastResultOrError: T; + for (let i = 0; i < retryCount; i++) { + const [ok, resultOrError] = await f() + .then(result => [true, result]) + .catch(err => [false, err]); + + lastOk = ok; + lastResultOrError = resultOrError; + + if (ok) { + break; + } + + // RATE_LIMIT_EXCEEDED + if (resultOrError?.id === 'd5826d14-3982-4d2e-8011-b9e9f02499ef') { + await sleep(resultOrError?.info?.fullResetMs ?? 1000); + continue; + } + + // Throw for non-throttling errors + throw resultOrError; + } + + if (lastOk) { + return lastResultOrError!; + } else { + // Give up after getting throttled too many times + throw lastResultOrError!; + } +} \ No newline at end of file diff --git a/packages/frontend/src/components/page/page.note.vue b/packages/frontend/src/components/page/page.note.vue index cc1075d42a..3a3c0e4c7b 100644 --- a/packages/frontend/src/components/page/page.note.vue +++ b/packages/frontend/src/components/page/page.note.vue @@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only