Skip to content

Commit

Permalink
Add retry mechanism to create amplify e2e test (aws-amplify#2220)
Browse files Browse the repository at this point in the history
* Add retry mechanism to create amplify e2e test

* Add retry mechanism to create amplify e2e test

* this.
  • Loading branch information
sobolk authored Nov 12, 2024
1 parent 38d6986 commit 9fd0642
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 37 deletions.
2 changes: 2 additions & 0 deletions .changeset/serious-spoons-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
runWithPackageManager,
} from './process-controller/process_controller.js';
import { amplifyAtTag } from './constants.js';
import { runWithRetry } from './retry.js';
import { RetryPredicates, runWithRetry } from './retry.js';

void describe('getting started happy path', async () => {
let branchBackendIdentifier: BackendIdentifier;
Expand Down Expand Up @@ -83,34 +83,21 @@ void describe('getting started happy path', async () => {
return;
}

await runWithRetry(
async () => {
if (packageManager === 'yarn-classic') {
await execa('yarn', ['add', 'create-amplify'], { cwd: tempDir });
await execaCommand(
'./node_modules/.bin/create-amplify --yes --debug',
{
cwd: tempDir,
env: { npm_config_user_agent: 'yarn/1.22.21' },
}
);
} else {
await runPackageManager(
packageManager,
['create', amplifyAtTag, '--yes'],
tempDir
).run();
}
},
(error) => {
// Retry on network-related errors or command failures
return (
error.message.includes('exit code 1') &&
(error.message.includes('aws-amplify') ||
error.message.includes('Command failed with exit code 1: yarn add'))
);
await runWithRetry(async () => {
if (packageManager === 'yarn-classic') {
await execa('yarn', ['add', 'create-amplify'], { cwd: tempDir });
await execaCommand('./node_modules/.bin/create-amplify --yes --debug', {
cwd: tempDir,
env: { npm_config_user_agent: 'yarn/1.22.21' },
});
} else {
await runPackageManager(
packageManager,
['create', amplifyAtTag, '--yes'],
tempDir
).run();
}
);
}, RetryPredicates.createAmplifyRetryPredicate);

const pathPrefix = path.join(tempDir, 'amplify');

Expand Down
28 changes: 27 additions & 1 deletion packages/integration-tests/src/retry.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type RetryPredicate = (error: Error) => boolean;

/**
* Executes an asynchronous operation with retry logic.
* This function attempts to execute the provided callable function multiple times
Expand All @@ -6,7 +8,7 @@
*/
export const runWithRetry = async <T>(
callable: () => Promise<T>,
retryPredicate: (error: Error) => boolean,
retryPredicate: RetryPredicate,
maxAttempts = 3
): Promise<T> => {
const collectedErrors: Error[] = [];
Expand All @@ -21,6 +23,10 @@ export const runWithRetry = async <T>(
if (!retryPredicate(error)) {
throw error;
}
} else {
// re-throw non-Error.
// This should never happen, but we should be aware if it does.
throw error;
}
}
}
Expand All @@ -30,3 +36,23 @@ export const runWithRetry = async <T>(
`All ${maxAttempts} attempts failed`
);
};

/**
* Known retry predicates that repeat in multiple places.
*/
export class RetryPredicates {
static createAmplifyRetryPredicate: RetryPredicate = (
error: Error
): boolean => {
const message = error.message.toLowerCase();
// Note: we can't assert on whole stdout or stderr because
// they're not always captured in the error due to settings we need for
// ProcessController to work.
const didProcessExitWithError = message.includes('exit code 1');
const isKnownProcess =
(message.includes('yarn add') && message.includes('aws-amplify')) ||
message.includes('npm create amplify') ||
message.includes('pnpm create amplify');
return didProcessExitWithError && isKnownProcess;
};
}
19 changes: 11 additions & 8 deletions packages/integration-tests/src/test-e2e/create_amplify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { testConcurrencyLevel } from './test_concurrency.js';
import { findBaselineCdkVersion } from '../cdk_version_finder.js';
import { amplifyAtTag } from '../constants.js';
import { NpmProxyController } from '../npm_proxy_controller.js';
import { RetryPredicates, runWithRetry } from '../retry.js';

void describe(
'create-amplify script',
Expand Down Expand Up @@ -78,14 +79,16 @@ void describe(
);
}

await execa(
'npm',
['create', amplifyAtTag, '--yes', '--', '--debug'],
{
cwd: tempDir,
stdio: 'inherit',
}
);
await runWithRetry(async () => {
await execa(
'npm',
['create', amplifyAtTag, '--yes', '--', '--debug'],
{
cwd: tempDir,
stdio: 'inherit',
}
);
}, RetryPredicates.createAmplifyRetryPredicate);

// Override CDK installation with baseline version
await execa(
Expand Down

0 comments on commit 9fd0642

Please sign in to comment.