Skip to content

Commit b03f2c1

Browse files
abettadapurdevelar
authored andcommitted
fix(builder-util): Retry flaky builder operations
Close #4657
1 parent 07693b3 commit b03f2c1

File tree

2 files changed

+54
-29
lines changed

2 files changed

+54
-29
lines changed

packages/app-builder-lib/src/winPackager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ export class WinPackager extends PlatformPackager<WindowsConfiguration> {
317317
const timer = time("wine&sign")
318318
// rcedit crashed of executed using wine, resourcehacker works
319319
if (process.platform === "win32" || this.info.framework.name === "electron") {
320-
await executeAppBuilder(["rcedit", "--args", JSON.stringify(args)])
320+
await executeAppBuilder(["rcedit", "--args", JSON.stringify(args)], undefined /* child-process */, {}, 3 /* retry five times */)
321321
}
322322

323323
await this.sign(file)

packages/builder-util/src/util.ts

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -334,36 +334,61 @@ export class InvalidConfigurationError extends Error {
334334
}
335335
}
336336

337-
export function executeAppBuilder(args: Array<string>, childProcessConsumer?: (childProcess: ChildProcess) => void, extraOptions: SpawnOptions = {}): Promise<string> {
338-
return new Promise<string>((resolve, reject) => {
339-
const command = appBuilderPath
340-
const env: any = {
341-
...process.env,
342-
SZA_PATH: path7za,
343-
FORCE_COLOR: chalk.level === 0 ? "0" : "1",
344-
}
345-
const cacheEnv = process.env.ELECTRON_BUILDER_CACHE
346-
if (cacheEnv != null && cacheEnv.length > 0) {
347-
env.ELECTRON_BUILDER_CACHE = path.resolve(cacheEnv)
348-
}
337+
export function executeAppBuilder(args: Array<string>, childProcessConsumer?: (childProcess: ChildProcess) => void, extraOptions: SpawnOptions = {}, maxRetries = 0): Promise<string> {
338+
const command = appBuilderPath
339+
const env: any = {
340+
...process.env,
341+
SZA_PATH: path7za,
342+
FORCE_COLOR: chalk.level === 0 ? "0" : "1",
343+
}
344+
const cacheEnv = process.env.ELECTRON_BUILDER_CACHE
345+
if (cacheEnv != null && cacheEnv.length > 0) {
346+
env.ELECTRON_BUILDER_CACHE = path.resolve(cacheEnv)
347+
}
349348

350-
if (extraOptions.env != null) {
351-
Object.assign(env, extraOptions.env)
352-
}
349+
if (extraOptions.env != null) {
350+
Object.assign(env, extraOptions.env)
351+
}
353352

354-
const childProcess = doSpawn(command, args, {
355-
env,
356-
stdio: ["ignore", "pipe", process.stdout],
357-
...extraOptions,
358-
})
359-
if (childProcessConsumer != null) {
360-
childProcessConsumer(childProcess)
361-
}
362-
handleProcess("close", childProcess, command, resolve, error => {
363-
if (error instanceof ExecError && error.exitCode === 2) {
364-
error.alreadyLogged = true
353+
function runCommand() {
354+
return new Promise<string>((resolve, reject) => {
355+
const childProcess = doSpawn(command, args, {
356+
env,
357+
stdio: ["ignore", "pipe", process.stdout],
358+
...extraOptions
359+
})
360+
if (childProcessConsumer != null) {
361+
childProcessConsumer(childProcess)
365362
}
366-
reject(error)
363+
handleProcess("close", childProcess, command, resolve, error => {
364+
if (error instanceof ExecError && error.exitCode === 2) {
365+
error.alreadyLogged = true
366+
}
367+
reject(error)
368+
})
367369
})
368-
})
370+
}
371+
372+
if (maxRetries === 0) {
373+
return runCommand()
374+
}
375+
else {
376+
return retry(runCommand, maxRetries, 1000)
377+
}
369378
}
379+
380+
async function retry<T>(task: () => Promise<T>, retriesLeft: number, interval: number): Promise<T> {
381+
try {
382+
return await task()
383+
}
384+
catch (error) {
385+
log.info(`Above command failed, retrying ${retriesLeft} more times`)
386+
if (retriesLeft > 0) {
387+
await new Promise(resolve => setTimeout(resolve, interval))
388+
return await retry(task, retriesLeft - 1, interval)
389+
}
390+
else {
391+
throw error
392+
}
393+
}
394+
}

0 commit comments

Comments
 (0)