Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: s3 upload index.html at last #12852

Merged
merged 10 commits into from
Jun 26, 2023
Merged

fix: s3 upload index.html at last #12852

merged 10 commits into from
Jun 26, 2023

Conversation

0618
Copy link
Contributor

@0618 0618 commented Jun 22, 2023

Description of changes

This PR is to mitigate #2087 as proposed by @timoteialbu .

Issue: since index.html is not always uploaded to S3 at last, it sometimes causes file not found issue if a dependent file is uploaded after index.html

Fix: await Promise.all all other files except index.html, then upload index.html at the end.

Note:

  1. This PR is just a mitigation. To fundamentally resolve the issue, users need to enable some sort of cache or versionize.
  2. I've checked some popular build tools and they all use index.html. The build tools I checked are: angular-cli@16, react@18.2.0 + cra@5.0.1, react + next@13.4.7, react + vite@4.3.9, vue@3.3.4, vue + nuxt@3.5.2, vue + vite@4.3.9

Issue #, if available

#2087

Description of how you validated changes

Checklist

  • PR description included
  • yarn test passes
  • Tests are changed or added
  • Relevant documentation is changed or added (and PR referenced)
  • New AWS SDK calls or CloudFormation actions have been added to relevant test and service IAM policies
  • Pull request labels are added

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@codecov-commenter
Copy link

codecov-commenter commented Jun 22, 2023

Codecov Report

Merging #12852 (ad83cd4) into dev (ec9a2ba) will increase coverage by 48.51%.
The diff coverage is 59.05%.

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

@@             Coverage Diff             @@
##              dev   #12852       +/-   ##
===========================================
+ Coverage    0.00%   48.51%   +48.51%     
===========================================
  Files        1296      842      -454     
  Lines      149743    38091   -111652     
  Branches     1296     7755     +6459     
===========================================
+ Hits            0    18480    +18480     
+ Misses     148447    18021   -130426     
- Partials     1296     1590      +294     
Impacted Files Coverage Δ
...ify-category-function/src/events/prePushHandler.ts 33.33% <0.00%> (+33.33%) ⬆️
...ider-utils/awscloudformation/utils/layerHelpers.ts 21.80% <0.00%> (+21.80%) ⬆️
...ib/S3AndCloudFront/helpers/configure-CloudFront.js 87.06% <ø> (+87.06%) ⬆️
...lify-category-hosting/lib/S3AndCloudFront/index.js 89.65% <ø> (+89.65%) ⬆️
...ifications/src/commands/notifications/configure.ts 0.00% <0.00%> (ø)
...e/src/amplify-node-pkg-detector/lock-file-types.ts 100.00% <ø> (+100.00%) ⬆️
.../src/amplify-node-pkg-detector/yarn-lock-parser.ts 100.00% <ø> (+100.00%) ⬆️
packages/amplify-cli-core/src/constants.ts 100.00% <ø> (+100.00%) ⬆️
...es/amplify-cli-core/src/context/plugin-platform.ts 33.33% <0.00%> (+33.33%) ⬆️
...s/amplify-cli-core/src/errors/amplify-exception.ts 82.35% <ø> (+82.35%) ⬆️
... and 37 more

... and 1258 files with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@0618 0618 marked this pull request as ready for review June 22, 2023 19:41
@0618 0618 requested a review from a team as a code owner June 22, 2023 19:41
Comment on lines 22 to 29

await Promise.all(fileList.map(async filePath => {
if(!filePath.includes('index.html')) {
return await uploadFileTasks.push(() => uploadFile(s3Client, hostingBucketName, distributionDirPath, filePath, hasCloudFront));
}}));

fileList.filter(filePath => filePath.includes('index.html')).forEach(filePath => {
uploadFileTasks.push(() => uploadFile(s3Client, hostingBucketName, distributionDirPath, filePath, hasCloudFront));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to refactor this into two sections for better readability. something like

const indexFile = ... select index from fileList...;
const otherFiles = ... select all other files from fileList....;

await Promise.all(...upload all files...);
await upload(index);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 3abfb51

lazpavel
lazpavel previously approved these changes Jun 22, 2023
Comment on lines 25 to 27
await Promise.all(filesToUploadFirst.map(async filePath => {
return uploadFileTasks.push(() => uploadFile(s3Client, hostingBucketName, distributionDirPath, filePath, hasCloudFront));
}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed this the first time, but please move this inside the try/catch after the spinner starts so customers can see something is uploading

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it doesn't matter for the user because sequential runs after the spinner and we have to push to the uploadFileTasks first

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not notice that sequential before and that we're accumulating deferred () => uploadFile callbacks. Sorry about that.

If actual upload happens in sequential and we'll never parallelize it then perhaps we should just make sure fileList has elements in right order.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider just concatenating filesToUploadFirst.concat(filesToUploadLast) and feeding this to logic that was here before. We don't need two mappings nor Promise.all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I just noticed sequential when making the previous comment 😂

Now I wonder if sequential is necessary. What's the purpose of sequential? Would it make the load too slow?

If we want to control the concurrency, would it be better to use promise-pool instead?

@@ -34,6 +32,13 @@ async function run(context, distributionDirPath) {
}
}

function sortUploadFiles(fileList) {
const filesToUploadLast = "index.html";
const sortFiles = (fileA, fileB) => fileA.includes(filesToUploadLast) ? 1 : fileB.includes(filesToUploadLast) ? -1 : 0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add prettier in another PR

Comment on lines 79 to 81
exportForTesting: {
sortUploadFiles,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not do this. I.e. don't open internals.
instead we should mock modules that are imported into uploader and assert order of s3Client.upload calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done e4ab460

Copy link
Member

@sobolk sobolk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Please address remaining comment.

fs.createReadStream = jest.fn(() => {
return {};
});
mime.lookup = jest.fn(() => {
return 'text/plain';
});
await fileUploader.run(mockContext, 'mockDistributionFolder');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the "functionality under test" should not be in beforeAll block, that block is reserved for test setup.
Readability of the tests (i.e. right call in right block) should take precedence over duplication.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done ada487f

@0618 0618 merged commit 99aff47 into aws-amplify:dev Jun 26, 2023
18 of 20 checks passed
@0618 0618 deleted the fix-issue-2087 branch June 26, 2023 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants