Skip to content

Commit e7f6f07

Browse files
cipolleschifacebook-github-bot
authored andcommitted
Implement retry mechanism during yarn installation (#39020)
Summary: Pull Request resolved: #39020 Sometimes yarn fails to intall, we are implementing a retry mechanism ## Changelog: [Internal] - Add retry mechanism in template jobs. Reviewed By: cortinico Differential Revision: D48234860 fbshipit-source-id: ece3c40051ff143837ed79db2390fbb599fa8ae2
1 parent 623f44c commit e7f6f07

File tree

3 files changed

+109
-60
lines changed

3 files changed

+109
-60
lines changed

scripts/circleci/retry.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @oncall react-native
9+
*/
10+
11+
const {spawnSync} = require('child_process');
12+
13+
async function retry(command, options, maxRetries, delay, args) {
14+
for (let i = 1; i <= maxRetries; i++) {
15+
console.log(`Attempt ${i}: ${command}`);
16+
const result = spawnSync(command, args ? args : [], options);
17+
18+
if (result.status === 0) {
19+
console.log(`Command succeeded on attempt ${i}`);
20+
return true;
21+
}
22+
23+
console.log(`Command failed on attempt ${i}`);
24+
25+
if (i >= maxRetries) {
26+
console.log('Maximum retries reached. Exiting.');
27+
return false;
28+
}
29+
30+
if (delay > 0) {
31+
console.log(`Sleeping for ${delay} seconds...`);
32+
await new Promise(resolve => setTimeout(resolve, delay));
33+
}
34+
35+
console.log('Retrying...');
36+
}
37+
}
38+
39+
module.exports = {
40+
retry,
41+
};

scripts/circleci/run_with_retry.js

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,17 @@
77
* @format
88
*/
99

10-
const {spawnSync} = require('child_process');
10+
const {retry} = require('./retry');
1111

12-
function retryCommand(maxRetries, command) {
13-
for (let i = 1; i <= maxRetries; i++) {
14-
console.log(`Attempt ${i}: ${command}`);
15-
const result = spawnSync(command, {shell: true, stdio: 'inherit'});
16-
17-
if (result.status === 0) {
18-
console.log(`Command succeeded on attempt ${i}`);
19-
process.exit(0);
20-
} else {
21-
console.log(`Command failed on attempt ${i}`);
22-
if (i < maxRetries) {
23-
console.log('Retrying...');
24-
} else {
25-
console.log('Maximum retries reached. Exiting.');
26-
process.exit(1);
27-
}
28-
}
12+
async function retryCommand(maxRetries, command) {
13+
const success = await retry(
14+
command,
15+
{shell: true, stdio: 'inherit'},
16+
maxRetries,
17+
0,
18+
);
19+
if (!success) {
20+
process.exit(1);
2921
}
3022
}
3123

scripts/template/initialize.js

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
'use strict';
1111

1212
const yargs = require('yargs');
13-
const {execSync, spawnSync} = require('child_process');
13+
const {execSync} = require('child_process');
1414

1515
const forEachPackage = require('../monorepo/for-each-package');
1616
const setupVerdaccio = require('../setup-verdaccio');
17+
const {retry} = require('../circleci/retry');
1718

1819
const {argv} = yargs
1920
.option('r', {
@@ -42,54 +43,69 @@ const {reactNativeRootPath, templateName, templateConfigPath, directory} = argv;
4243

4344
const VERDACCIO_CONFIG_PATH = `${reactNativeRootPath}/.circleci/verdaccio.yml`;
4445

45-
function install() {
46+
async function install() {
4647
const VERDACCIO_PID = setupVerdaccio(
4748
reactNativeRootPath,
4849
VERDACCIO_CONFIG_PATH,
4950
);
50-
process.stdout.write('Bootstrapped Verdaccio \u2705\n');
51-
52-
process.stdout.write('Starting to publish every package...\n');
53-
forEachPackage(
54-
(packageAbsolutePath, packageRelativePathFromRoot, packageManifest) => {
55-
if (packageManifest.private) {
56-
return;
57-
}
58-
59-
execSync('npm publish --registry http://localhost:4873 --access public', {
60-
cwd: packageAbsolutePath,
51+
try {
52+
process.stdout.write('Bootstrapped Verdaccio \u2705\n');
53+
54+
process.stdout.write('Starting to publish every package...\n');
55+
forEachPackage(
56+
(packageAbsolutePath, packageRelativePathFromRoot, packageManifest) => {
57+
if (packageManifest.private) {
58+
return;
59+
}
60+
61+
execSync(
62+
'npm publish --registry http://localhost:4873 --access public',
63+
{
64+
cwd: packageAbsolutePath,
65+
stdio: [process.stdin, process.stdout, process.stderr],
66+
},
67+
);
68+
69+
process.stdout.write(
70+
`Published ${packageManifest.name} to proxy \u2705\n`,
71+
);
72+
},
73+
);
74+
75+
process.stdout.write('Published every package \u2705\n');
76+
77+
execSync(
78+
`node cli.js init ${templateName} --directory ${directory} --template ${templateConfigPath} --verbose --skip-install`,
79+
{
80+
cwd: `${reactNativeRootPath}/packages/react-native`,
6181
stdio: [process.stdin, process.stdout, process.stderr],
62-
});
63-
64-
process.stdout.write(
65-
`Published ${packageManifest.name} to proxy \u2705\n`,
66-
);
67-
},
68-
);
69-
70-
process.stdout.write('Published every package \u2705\n');
82+
},
83+
);
84+
process.stdout.write('Completed initialization of template app \u2705\n');
7185

72-
execSync(
73-
`node cli.js init ${templateName} --directory ${directory} --template ${templateConfigPath} --verbose --skip-install`,
74-
{
75-
cwd: `${reactNativeRootPath}/packages/react-native`,
86+
process.stdout.write('Installing dependencies in template app folder...\n');
87+
const options = {
88+
cwd: directory,
7689
stdio: [process.stdin, process.stdout, process.stderr],
77-
},
78-
);
79-
process.stdout.write('Completed initialization of template app \u2705\n');
80-
81-
process.stdout.write('Installing dependencies in template app folder...\n');
82-
spawnSync('yarn', ['install'], {
83-
cwd: directory,
84-
stdio: [process.stdin, process.stdout, process.stderr],
85-
});
86-
process.stdout.write('Installed dependencies via Yarn \u2705\n');
90+
};
91+
const success = await retry('yarn', options, 3, 500, ['install']);
8792

88-
process.stdout.write(`Killing verdaccio. PID — ${VERDACCIO_PID}...\n`);
89-
execSync(`kill -9 ${VERDACCIO_PID}`);
90-
process.stdout.write('Killed Verdaccio process \u2705\n');
91-
92-
process.exit();
93+
if (!success) {
94+
process.stdout.write(
95+
'Failed to install dependencies in template app folder.',
96+
);
97+
throw new Error('Failed to install dependencies in template app folder.');
98+
}
99+
100+
process.stdout.write('Installed dependencies via Yarn \u2705\n');
101+
} finally {
102+
process.stdout.write(`Killing verdaccio. PID — ${VERDACCIO_PID}...\n`);
103+
execSync(`kill -9 ${VERDACCIO_PID}`);
104+
process.stdout.write('Killed Verdaccio process \u2705\n');
105+
}
93106
}
94107

95-
install();
108+
install().then(() => {
109+
console.log('Done with preparing the project.');
110+
process.exit();
111+
});

0 commit comments

Comments
 (0)