Graceful rimraf in updater

This commit is contained in:
Fedor Indutny 2023-03-02 09:57:36 -08:00 committed by GitHub
parent c488b626bf
commit 1e7d658109
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 39 deletions

View file

@ -5,6 +5,8 @@ import { createReadStream } from 'fs';
import { rename } from 'fs/promises';
import { pipeline } from 'stream/promises';
import { createHash } from 'crypto';
import rimraf from 'rimraf';
import { promisify } from 'util';
import * as Errors from '../types/errors';
import type { LoggerType } from '../types/Logging';
@ -12,6 +14,8 @@ import * as durations from '../util/durations';
import { isOlderThan } from '../util/timestamp';
import { sleep } from '../util/sleep';
const rimrafPromise = promisify(rimraf);
export type CheckIntegrityResultType = Readonly<
| {
ok: true;
@ -48,30 +52,32 @@ export async function checkIntegrity(
}
}
async function doGracefulRename({
async function doGracefulFSOperation<Args extends ReadonlyArray<unknown>>({
name,
operation,
args,
logger,
fromPath,
toPath,
startedAt,
retryCount,
retryAfter = 5 * durations.SECOND,
timeout = 5 * durations.MINUTE,
}: {
name: string;
operation: (...args: Args) => Promise<void>;
args: Args;
logger: LoggerType;
fromPath: string;
toPath: string;
startedAt: number;
retryCount: number;
retryAfter?: number;
timeout?: number;
}): Promise<void> {
const logId = `gracefulFS(${name})`;
try {
await rename(fromPath, toPath);
await operation(...args);
if (retryCount !== 0) {
logger.info(
`gracefulRename: succeeded after ${retryCount} retries, renamed ` +
`${fromPath} to ${toPath}`
`${logId}: succeeded after ${retryCount} retries, ${args.join(', ')}`
);
}
} catch (error) {
@ -80,25 +86,22 @@ async function doGracefulRename({
}
if (isOlderThan(startedAt, timeout)) {
logger.warn(
'gracefulRename: timed out while retrying renaming ' +
`${fromPath} to ${toPath}`
);
logger.warn(`${logId}: timed out, ${args.join(', ')}`);
throw error;
}
logger.warn(
`gracefulRename: got ${error.code} when renaming ` +
`${fromPath} to ${toPath}, retrying in one second. ` +
`(retryCount=${retryCount})`
`${logId}: got ${error.code} when running on ${args.join(', ')}; ` +
`retrying in one second. (retryCount=${retryCount})`
);
await sleep(retryAfter);
return doGracefulRename({
return doGracefulFSOperation({
name,
operation,
args,
logger,
fromPath,
toPath,
startedAt,
retryCount: retryCount + 1,
retryAfter,
@ -112,10 +115,25 @@ export async function gracefulRename(
fromPath: string,
toPath: string
): Promise<void> {
return doGracefulRename({
return doGracefulFSOperation({
name: 'rename',
operation: rename,
args: [fromPath, toPath],
logger,
startedAt: Date.now(),
retryCount: 0,
});
}
export async function gracefulRimraf(
logger: LoggerType,
path: string
): Promise<void> {
return doGracefulFSOperation({
name: 'rimraf',
operation: rimrafPromise,
args: [path],
logger,
fromPath,
toPath,
startedAt: Date.now(),
retryCount: 0,
});