This commit is contained in:
Manav Rathi 2024-11-25 11:19:36 +05:30
parent 0ee657af1a
commit b80b91b6cd
No known key found for this signature in database
7 changed files with 56 additions and 50 deletions

View File

@ -1,7 +1,7 @@
import log from "@/base/log";
import { apiURL } from "@/base/origins";
import { retryAsyncOperation } from "@/gallery/utils/retry-async";
import { EnteFile } from "@/media/file";
import { retryAsyncOperation } from "@/utils/promise";
import { CustomError, handleUploadError } from "@ente/shared/error";
import HTTPService from "@ente/shared/network/HTTPService";
import { MultipartUploadURLs, UploadFile, UploadURL } from "./upload-service";

View File

@ -1,7 +1,7 @@
import log from "@/base/log";
import { apiURL, uploaderOrigin } from "@/base/origins";
import { retryAsyncOperation } from "@/gallery/utils/retry-async";
import { EnteFile } from "@/media/file";
import { retryAsyncOperation } from "@/utils/promise";
import { CustomError, handleUploadError } from "@ente/shared/error";
import HTTPService from "@ente/shared/network/HTTPService";
import { getToken } from "@ente/shared/storage/localStorage/helpers";

View File

@ -1,3 +1,4 @@
import { retryAsyncOperation } from "@/utils/promise";
import { clientPackageName } from "./app";
import { ensureAuthToken } from "./local-user";
@ -66,3 +67,17 @@ export const ensureOk = (res: Response) => {
*/
export const isHTTP4xxError = (e: unknown) =>
e instanceof HTTPError && e.res.status >= 400 && e.res.status <= 499;
/**
* A helper function to adapt {@link retryAsyncOperation} for HTTP fetches.
*
* This will ensure that the HTTP operation returning a non-200 OK status (as
* matched by {@link ensureOk}) is also counted as an error when considering if
* a request should be retried.
*/
export const retryEnsuringHTTPOk = (request: () => Promise<Response>) =>
retryAsyncOperation(async () => {
const r = await request();
ensureOk(r);
return r;
});

View File

@ -3,6 +3,7 @@
"version": "0.0.0",
"private": true,
"dependencies": {
"@/utils": "*",
"@emotion/react": "11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/icons-material": "^5.16.6",

View File

@ -1,37 +1 @@
import { wait } from "@/utils/promise";
/**
* Retry a async operation like a HTTP request 3 (+ 1 original) times with
* exponential backoff.
*
* @param op A function that performs the operation, returning the promise for
* its completion.
*
* @param abortIfNeeded An optional function that is called with the
* corresponding error whenever {@link op} rejects. It should throw the error if
* the retries should immediately be aborted.
*
* @returns A promise that fulfills with to the result of a first successfully
* fulfilled promise of the 4 (1 + 3) attempts, or rejects with the error
* obtained either when {@link abortIfNeeded} throws, or with the error from the
* last attempt otherwise.
*/
export const retryAsyncOperation = async <T>(
op: () => Promise<T>,
abortIfNeeded?: (error: unknown) => void,
): Promise<T> => {
const waitTimeBeforeNextTry = [2000, 5000, 10000];
while (true) {
try {
return await op();
} catch (e) {
if (abortIfNeeded) {
abortIfNeeded(e);
}
const t = waitTimeBeforeNextTry.shift();
if (!t) throw e;
await wait(t);
}
}
};

View File

@ -9,7 +9,7 @@ import {
import {
authenticatedRequestHeaders,
clientPackageHeader,
ensureOk,
retryEnsuringHTTPOk,
} from "@/base/http";
import { ensureAuthToken } from "@/base/local-user";
import log from "@/base/log";
@ -18,7 +18,6 @@ import {
playableVideoBlob,
renderableImageBlob,
} from "@/gallery/utils/convert";
import { retryAsyncOperation } from "@/gallery/utils/retry-async";
import type { EnteFile } from "@/media/file";
import { FileType } from "@/media/file-type";
import { decodeLivePhoto } from "@/media/live-photo";
@ -589,16 +588,6 @@ async function getRenderableLivePhotoURL(
};
}
/**
* A helper function to adapt {@link retryAsyncOperation} for HTTP fetches.
*/
const retryEnsuringHTTPOk = (request: () => Promise<Response>) =>
retryAsyncOperation(async () => {
const r = await request();
ensureOk(r);
return r;
});
/**
* The various photos_* functions are used for the actual downloads when
* we're running in the context of the the photos app.

View File

@ -107,6 +107,43 @@ export const withTimeout = async <T>(promise: Promise<T>, ms: number) => {
return Promise.race([promiseAndCancelTimeout(), rejectOnTimeout]);
};
/**
* Retry a async operation like a HTTP request 3 (+ 1 original) times with
* exponential backoff.
*
* @param op A function that performs the operation, returning the promise for
* its completion.
*
* @param abortIfNeeded An optional function that is called with the
* corresponding error whenever {@link op} rejects. It should throw the error if
* the retries should immediately be aborted.
*
* @returns A promise that fulfills with to the result of a first successfully
* fulfilled promise of the 4 (1 + 3) attempts, or rejects with the error
* obtained either when {@link abortIfNeeded} throws, or with the error from the
* last attempt otherwise.
*/
export const retryAsyncOperation = async <T>(
op: () => Promise<T>,
abortIfNeeded?: (error: unknown) => void,
): Promise<T> => {
const waitTimeBeforeNextTry = [2000, 5000, 10000];
while (true) {
try {
return await op();
} catch (e) {
if (abortIfNeeded) {
abortIfNeeded(e);
}
const t = waitTimeBeforeNextTry.shift();
if (!t) throw e;
await wait(t);
}
}
};
/**
* A promise queue to serialize execution of bunch of promises.
*