Skip to content

Commit

Permalink
fix: retry renaming update file when EBUSY error occurs due to file l…
Browse files Browse the repository at this point in the history
…ock (#8437)
  • Loading branch information
juwonjung-hdj authored Sep 5, 2024
1 parent d5d9f3f commit be625e0
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 13 deletions.
7 changes: 7 additions & 0 deletions .changeset/serious-kings-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"builder-util": patch
"builder-util-runtime": patch
"electron-updater": patch
---

fix: retry renaming update file when EBUSY error occurs due to file lock
1 change: 1 addition & 0 deletions packages/builder-util-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export { parseXml, XElement } from "./xml"
export { BlockMap } from "./blockMapApi"
export { newError } from "./error"
export { MemoLazy } from "./MemoLazy"
export { retry } from "./retry"

// nsis
export const CURRENT_APP_INSTALLER_FILE_NAME = "installer.exe"
Expand Down
15 changes: 15 additions & 0 deletions packages/builder-util-runtime/src/retry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CancellationToken } from "./CancellationToken"

export async function retry<T>(task: () => Promise<T>, retryCount: number, interval: number, backoff = 0, attempt = 0, shouldRetry?: (e: any) => boolean): Promise<T> {
const cancellationToken = new CancellationToken()
try {
return await task()
} catch (error: any) {
if ((shouldRetry?.(error) ?? true) && retryCount > 0 && !cancellationToken.cancelled) {
await new Promise(resolve => setTimeout(resolve, interval + backoff * attempt))
return await retry(task, retryCount - 1, interval, backoff, attempt + 1, shouldRetry)
} else {
throw error
}
}
}
16 changes: 4 additions & 12 deletions packages/builder-util/src/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { appBuilderPath } from "app-builder-bin"
import { CancellationToken, safeStringifyJson } from "builder-util-runtime"
import { safeStringifyJson, retry as _retry } from "builder-util-runtime"
import * as chalk from "chalk"
import { ChildProcess, execFile, ExecFileOptions, SpawnOptions } from "child_process"
import { spawn as _spawn } from "cross-spawn"
Expand Down Expand Up @@ -408,16 +408,8 @@ export async function executeAppBuilder(
}

export async function retry<T>(task: () => Promise<T>, retryCount: number, interval: number, backoff = 0, attempt = 0, shouldRetry?: (e: any) => boolean): Promise<T> {
const cancellationToken = new CancellationToken()
try {
return await task()
} catch (error: any) {
return await _retry(task, retryCount, interval, backoff, attempt, e => {
log.info(`Above command failed, retrying ${retryCount} more times`)
if ((shouldRetry?.(error) ?? true) && retryCount > 0 && !cancellationToken.cancelled) {
await new Promise(resolve => setTimeout(resolve, interval + backoff * attempt))
return await retry(task, retryCount - 1, interval, backoff, attempt + 1, shouldRetry)
} else {
throw error
}
}
return shouldRetry?.(e) ?? true
})
}
10 changes: 9 additions & 1 deletion packages/electron-updater/src/AppUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
CancellationError,
ProgressInfo,
BlockMap,
retry,
} from "builder-util-runtime"
import { randomBytes } from "crypto"
import { release } from "os"
Expand Down Expand Up @@ -712,7 +713,14 @@ export abstract class AppUpdater extends (EventEmitter as new () => TypedEmitter
const tempUpdateFile = await createTempUpdateFile(`temp-${updateFileName}`, cacheDir, log)
try {
await taskOptions.task(tempUpdateFile, downloadOptions, packageFile, removeFileIfAny)
await rename(tempUpdateFile, updateFile)
await retry(
() => rename(tempUpdateFile, updateFile),
60,
500,
0,
0,
error => error instanceof Error && /^EBUSY:/.test(error.message)
)
} catch (e: any) {
await removeFileIfAny()

Expand Down

0 comments on commit be625e0

Please sign in to comment.