mirror of
https://github.com/ente-io/ente.git
synced 2025-08-05 05:24:26 +00:00
Merge
This commit is contained in:
parent
aa3c212b26
commit
3578ed1eef
@ -1,6 +1,6 @@
|
||||
import log from "@/base/log";
|
||||
import { apiURL } from "@/base/origins";
|
||||
import { retryHTTPCall } from "@/gallery/retry-async";
|
||||
import { retryAsyncOperation } from "@/gallery/retry-async";
|
||||
import { EnteFile } from "@/media/file";
|
||||
import { CustomError, handleUploadError } from "@ente/shared/error";
|
||||
import HTTPService from "@ente/shared/network/HTTPService";
|
||||
@ -21,7 +21,7 @@ class PublicUploadHttpClient {
|
||||
throw Error(CustomError.TOKEN_MISSING);
|
||||
}
|
||||
const url = await apiURL("/public-collection/file");
|
||||
const response = await retryHTTPCall(
|
||||
const response = await retryAsyncOperation(
|
||||
() =>
|
||||
HTTPService.post(url, uploadFile, null, {
|
||||
"X-Auth-Access-Token": token,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import log from "@/base/log";
|
||||
import { apiURL, uploaderOrigin } from "@/base/origins";
|
||||
import { retryHTTPCall } from "@/gallery/retry-async";
|
||||
import { retryAsyncOperation } from "@/gallery/retry-async";
|
||||
import { EnteFile } from "@/media/file";
|
||||
import { CustomError, handleUploadError } from "@ente/shared/error";
|
||||
import HTTPService from "@ente/shared/network/HTTPService";
|
||||
@ -17,7 +17,7 @@ class UploadHttpClient {
|
||||
return;
|
||||
}
|
||||
const url = await apiURL("/files");
|
||||
const response = await retryHTTPCall(
|
||||
const response = await retryAsyncOperation(
|
||||
() =>
|
||||
HTTPService.post(url, uploadFile, null, {
|
||||
"X-Auth-Token": token,
|
||||
@ -90,7 +90,7 @@ class UploadHttpClient {
|
||||
progressTracker,
|
||||
): Promise<string> {
|
||||
try {
|
||||
await retryHTTPCall(
|
||||
await retryAsyncOperation(
|
||||
() =>
|
||||
HTTPService.put(
|
||||
fileUploadURL.url,
|
||||
@ -117,7 +117,7 @@ class UploadHttpClient {
|
||||
): Promise<string> {
|
||||
try {
|
||||
const origin = await uploaderOrigin();
|
||||
await retryHTTPCall(() =>
|
||||
await retryAsyncOperation(() =>
|
||||
HTTPService.put(
|
||||
`${origin}/file-upload`,
|
||||
file,
|
||||
@ -143,7 +143,7 @@ class UploadHttpClient {
|
||||
progressTracker,
|
||||
) {
|
||||
try {
|
||||
const response = await retryHTTPCall(async () => {
|
||||
const response = await retryAsyncOperation(async () => {
|
||||
const resp = await HTTPService.put(
|
||||
partUploadURL,
|
||||
filePart,
|
||||
@ -174,7 +174,7 @@ class UploadHttpClient {
|
||||
) {
|
||||
try {
|
||||
const origin = await uploaderOrigin();
|
||||
const response = await retryHTTPCall(async () => {
|
||||
const response = await retryAsyncOperation(async () => {
|
||||
const resp = await HTTPService.put(
|
||||
`${origin}/multipart-upload`,
|
||||
filePart,
|
||||
@ -202,7 +202,7 @@ class UploadHttpClient {
|
||||
|
||||
async completeMultipartUpload(completeURL: string, reqBody: any) {
|
||||
try {
|
||||
await retryHTTPCall(() =>
|
||||
await retryAsyncOperation(() =>
|
||||
HTTPService.post(completeURL, reqBody, null, {
|
||||
"content-type": "text/xml",
|
||||
}),
|
||||
@ -216,7 +216,7 @@ class UploadHttpClient {
|
||||
async completeMultipartUploadV2(completeURL: string, reqBody: any) {
|
||||
try {
|
||||
const origin = await uploaderOrigin();
|
||||
await retryHTTPCall(() =>
|
||||
await retryAsyncOperation(() =>
|
||||
HTTPService.post(
|
||||
`${origin}/multipart-complete`,
|
||||
reqBody,
|
||||
|
@ -1,48 +1,37 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-inferrable-types */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { wait } from "@/utils/promise";
|
||||
|
||||
const retrySleepTimeInMilliSeconds = [2000, 5000, 10000];
|
||||
|
||||
/**
|
||||
* Retry a HTTP request 3 (+ 1 original) times with exponential backoff.
|
||||
* Retry a async operation like a HTTP request 3 (+ 1 original) times with
|
||||
* exponential backoff.
|
||||
*
|
||||
* @param func A function that perform the operation, returning the promise for
|
||||
* @param op A function that performs the operation, returning the promise for
|
||||
* its completion.
|
||||
*
|
||||
* @param checkForBreakingError A function that is passed the error with which
|
||||
* {@link func} rejects. It should throw the error if the retries should
|
||||
* immediately be aborted.
|
||||
* @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 successfully
|
||||
* fulfilled promise of the 4 (1 + 3) attempts, or rejects with the error of
|
||||
* either when {@link checkForBreakingError} throws, or with the error from the
|
||||
* @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 async function retryHTTPCall(
|
||||
func: () => Promise<any>,
|
||||
checkForBreakingError?: (error: unknown) => void,
|
||||
): Promise<any> {
|
||||
const retrier = async (
|
||||
func: () => Promise<any>,
|
||||
attemptNumber: number = 0,
|
||||
) => {
|
||||
export const retryAsyncOperation = async <T>(
|
||||
op: () => Promise<T>,
|
||||
abortIfNeeded?: (error: unknown) => void,
|
||||
): Promise<T> => {
|
||||
const waitTimeBeforeNextTry = [2000, 5000, 10000];
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
const resp = await func();
|
||||
return resp;
|
||||
return await op();
|
||||
} catch (e) {
|
||||
if (checkForBreakingError) {
|
||||
checkForBreakingError(e);
|
||||
}
|
||||
if (attemptNumber < retrySleepTimeInMilliSeconds.length) {
|
||||
await wait(retrySleepTimeInMilliSeconds[attemptNumber]!);
|
||||
return await retrier(func, attemptNumber + 1);
|
||||
} else {
|
||||
throw e;
|
||||
if (abortIfNeeded) {
|
||||
abortIfNeeded(e);
|
||||
}
|
||||
const t = waitTimeBeforeNextTry.shift();
|
||||
if (!t) throw e;
|
||||
await wait(t);
|
||||
}
|
||||
};
|
||||
return await retrier(func);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@/base": "*",
|
||||
"@/gallery": "*",
|
||||
"@/utils": "*",
|
||||
"@ente/shared": "*",
|
||||
"@mui/x-date-pickers": "^7.16.0",
|
||||
|
@ -18,7 +18,7 @@ import * as ffmpeg from "@/new/photos/services/ffmpeg";
|
||||
import { renderableImageBlob } from "@/new/photos/utils/file";
|
||||
import { CustomError } from "@ente/shared/error";
|
||||
import HTTPService from "@ente/shared/network/HTTPService";
|
||||
import { retryAsyncFunction } from "@ente/shared/utils";
|
||||
import { retryAsyncOperation } from "@/gallery/retry-async";
|
||||
|
||||
export type OnDownloadProgress = (event: {
|
||||
loaded: number;
|
||||
@ -638,7 +638,7 @@ class PhotosDownloadClient implements DownloadClient {
|
||||
}
|
||||
};
|
||||
|
||||
const resp = await retryAsyncFunction(getThumbnail);
|
||||
const resp = await retryAsyncOperation(getThumbnail);
|
||||
if (resp.data === undefined) throw Error("request failed");
|
||||
// TODO: Remove this cast (it won't be needed when we migrate this from
|
||||
// axios to fetch).
|
||||
@ -680,7 +680,7 @@ class PhotosDownloadClient implements DownloadClient {
|
||||
}
|
||||
};
|
||||
|
||||
const resp = await retryAsyncFunction(getFile);
|
||||
const resp = await retryAsyncOperation(getFile);
|
||||
if (resp.data === undefined) throw Error("request failed");
|
||||
// TODO: Remove this cast (it won't be needed when we migrate this from
|
||||
// axios to fetch).
|
||||
@ -744,7 +744,7 @@ class PhotosDownloadClient implements DownloadClient {
|
||||
}
|
||||
};
|
||||
|
||||
return retryAsyncFunction(getFile);
|
||||
return retryAsyncOperation(getFile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -848,7 +848,7 @@ class PublicAlbumsDownloadClient implements DownloadClient {
|
||||
}
|
||||
};
|
||||
|
||||
const resp = await retryAsyncFunction(getFile);
|
||||
const resp = await retryAsyncOperation(getFile);
|
||||
if (resp.data === undefined) throw Error("request failed");
|
||||
// TODO: Remove this cast (it won't be needed when we migrate this from
|
||||
// axios to fetch).
|
||||
@ -887,6 +887,6 @@ class PublicAlbumsDownloadClient implements DownloadClient {
|
||||
}
|
||||
};
|
||||
|
||||
return retryAsyncFunction(getFile);
|
||||
return retryAsyncOperation(getFile);
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
import { wait } from "@/utils/promise";
|
||||
|
||||
export async function retryAsyncFunction<T>(
|
||||
request: (abort?: () => void) => Promise<T>,
|
||||
waitTimeBeforeNextTry?: number[],
|
||||
// Need to use @ts-ignore since this same file is currently included with
|
||||
// varying tsconfigs, and the error is only surfaced in the stricter ones of
|
||||
// them.
|
||||
//
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore TSC fails to detect that the exit of the loop is unreachable
|
||||
): Promise<T> {
|
||||
if (!waitTimeBeforeNextTry) waitTimeBeforeNextTry = [2000, 5000, 10000];
|
||||
|
||||
for (
|
||||
let attemptNumber = 0;
|
||||
attemptNumber <= waitTimeBeforeNextTry.length;
|
||||
attemptNumber++
|
||||
) {
|
||||
try {
|
||||
const resp = await request();
|
||||
return resp;
|
||||
} catch (e) {
|
||||
if (attemptNumber === waitTimeBeforeNextTry.length) {
|
||||
throw e;
|
||||
}
|
||||
await wait(waitTimeBeforeNextTry[attemptNumber]!);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user