Skip to content
This repository has been archived by the owner on May 3, 2024. It is now read-only.

Feat: ExpressJS to Fastify migration #878

Merged
merged 27 commits into from
Jan 31, 2023

Conversation

giulianok
Copy link
Member

@giulianok giulianok commented Dec 5, 2022

ExpressJS to Fastify migration. This is an internal change, API isn't being impacted.

Description

Migrating away from ExpressJS to improve performance, essentially be able to reduce time-to-start resolving a request, time-to-response, and handle more requests per second.

Small PRs have been raised for the team to easily review the changes:
#854
#856
#857
#859
#860
#865

This PR is the result of all these small PRs

Metrics

Fastify benchmark

Running 10s test @ http://localhost:3000/_/status (simple status check)
10 connections
┌─────────┬──────┬──────┬───────┬──────┬────────┬─────────┬───────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg    │ Stdev   │ Max   │
├─────────┼──────┼──────┼───────┼──────┼────────┼─────────┼───────┤
│ Latency │ 0 ms │ 0 ms │ 3 ms  │ 3 ms │ 0.6 ms │ 0.89 ms │ 32 ms │
└─────────┴──────┴──────┴───────┴──────┴────────┴─────────┴───────┘
┌───────────┬────────┬────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ Stat      │ 1%     │ 2.5%   │ 50%     │ 97.5%   │ Avg     │ Stdev   │ Min     │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Req/Sec   │ 4167   │ 4167   │ 8287    │ 8799    │ 7915.6  │ 1290.37 │ 4165    │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Bytes/Sec │ 2.1 MB │ 2.1 MB │ 4.17 MB │ 4.43 MB │ 3.98 MB │ 649 kB  │ 2.09 MB │
└───────────┴────────┴────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
Req/Bytes counts sampled once per second.
# of samples: 10
79k requests in 10.03s, 39.8 MB read
-------------------------------------------------------------------------------------
Running 10s test @ http://localhost:3000/html-partial/en-US/frank-the-parrot (HTML Partial)
10 connections
┌─────────┬──────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
│ Stat    │ 2.5% │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
├─────────┼──────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
│ Latency │ 9 ms │ 13 ms │ 31 ms │ 35 ms │ 14.81 ms │ 6.09 ms │ 75 ms │
└─────────┴──────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
┌───────────┬────────┬────────┬────────┬─────────┬────────┬────────┬────────┐
│ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%   │ Avg    │ Stdev  │ Min    │
├───────────┼────────┼────────┼────────┼─────────┼────────┼────────┼────────┤
│ Req/Sec   │ 412    │ 412    │ 627    │ 771     │ 653.3  │ 106.24 │ 412    │
├───────────┼────────┼────────┼────────┼─────────┼────────┼────────┼────────┤
│ Bytes/Sec │ 540 kB │ 540 kB │ 822 kB │ 1.01 MB │ 856 kB │ 139 kB │ 540 kB │
└───────────┴────────┴────────┴────────┴─────────┴────────┴────────┴────────┘
Req/Bytes counts sampled once per second.
# of samples: 10
7k requests in 10.02s, 8.56 MB read
-------------------------------------------------------------------------------------
Running 10s test @ http://localhost:3000/vitruvius (Full HTML Render)
10 connections
┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
│ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
│ Latency │ 10 ms │ 14 ms │ 33 ms │ 37 ms │ 16.39 ms │ 6.07 ms │ 65 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min     │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Req/Sec   │ 419     │ 419     │ 603     │ 659     │ 591.3   │ 68.74  │ 419     │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Bytes/Sec │ 4.15 MB │ 4.15 MB │ 5.97 MB │ 6.52 MB │ 5.85 MB │ 680 kB │ 4.14 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘
Req/Bytes counts sampled once per second.
# of samples: 10
6k requests in 10.02s, 58.5 MB read

Fastify runner + ExpressJS routes & logic (current implementation)

Running 10s test @ http://localhost:3000/_/status (simple status check)
10 connections
┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max   │
├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤
│ Latency │ 1 ms │ 2 ms │ 5 ms  │ 7 ms │ 2.39 ms │ 1.08 ms │ 22 ms │
└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min     │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Req/Sec   │ 2331    │ 2331    │ 3673    │ 4223    │ 3599.55 │ 538.4  │ 2330    │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Bytes/Sec │ 1.04 MB │ 1.04 MB │ 1.64 MB │ 1.88 MB │ 1.61 MB │ 240 kB │ 1.04 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘
Req/Bytes counts sampled once per second.
# of samples: 11
40k requests in 11.02s, 17.7 MB read
-------------------------------------------------------------------------------------
Running 10s test @ http://localhost:3000/html-partial/en-US/frank-the-parrot (HTML Partial)
10 connections
┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
│ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
│ Latency │ 11 ms │ 17 ms │ 37 ms │ 41 ms │ 18.54 ms │ 6.77 ms │ 82 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
┌───────────┬────────┬────────┬────────┬────────┬────────┬─────────┬────────┐
│ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg    │ Stdev   │ Min    │
├───────────┼────────┼────────┼────────┼────────┼────────┼─────────┼────────┤
│ Req/Sec   │ 373    │ 373    │ 521    │ 620    │ 524.9  │ 63.13   │ 373    │
├───────────┼────────┼────────┼────────┼────────┼────────┼─────────┼────────┤
│ Bytes/Sec │ 494 kB │ 494 kB │ 690 kB │ 821 kB │ 695 kB │ 83.6 kB │ 494 kB │
└───────────┴────────┴────────┴────────┴────────┴────────┴─────────┴────────┘
Req/Bytes counts sampled once per second.
# of samples: 10
5k requests in 10.02s, 6.95 MB read
-------------------------------------------------------------------------------------
Running 10s test @ http://localhost:3000/vitruvius (Full HTML Render)
10 connections
┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
│ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
│ Latency │ 12 ms │ 18 ms │ 39 ms │ 44 ms │ 19.85 ms │ 7.06 ms │ 76 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min     │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Req/Sec   │ 355     │ 355     │ 508     │ 553     │ 491     │ 51.83  │ 355     │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Bytes/Sec │ 3.51 MB │ 3.51 MB │ 5.02 MB │ 5.47 MB │ 4.85 MB │ 513 kB │ 3.51 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘
Req/Bytes counts sampled once per second.
# of samples: 10
5k requests in 10.03s, 48.5 MB read

ExpressJS only

This is just to provide some context of the Fastify improvement so far

Running 10s test @ http://localhost:3000/_/status
10 connections
┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max   │
├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤
│ Latency │ 1 ms │ 2 ms │ 6 ms  │ 7 ms │ 2.53 ms │ 1.24 ms │ 25 ms │
└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘
┌───────────┬────────┬────────┬─────────┬─────────┬─────────┬────────┬────────┐
│ Stat      │ 1%     │ 2.5%   │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min    │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼────────┼────────┤
│ Req/Sec   │ 2213   │ 2213   │ 3459    │ 3829    │ 3393.4  │ 445.87 │ 2213   │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼────────┼────────┤
│ Bytes/Sec │ 987 kB │ 987 kB │ 1.54 MB │ 1.71 MB │ 1.51 MB │ 199 kB │ 987 kB │
└───────────┴────────┴────────┴─────────┴─────────┴─────────┴────────┴────────┘
Req/Bytes counts sampled once per second.
# of samples: 10
34k requests in 10.02s, 15.1 MB read
Running 10s test @ http://localhost:3000/html-partial/en-US/frank-the-parrot
10 connections
┌─────────┬───────┬───────┬───────┬───────┬─────────┬─────────┬───────┐
│ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg     │ Stdev   │ Max   │
├─────────┼───────┼───────┼───────┼───────┼─────────┼─────────┼───────┤
│ Latency │ 12 ms │ 16 ms │ 36 ms │ 41 ms │ 18.2 ms │ 6.62 ms │ 97 ms │
└─────────┴───────┴───────┴───────┴───────┴─────────┴─────────┴───────┘
┌───────────┬────────┬────────┬────────┬────────┬────────┬─────────┬────────┐
│ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg    │ Stdev   │ Min    │
├───────────┼────────┼────────┼────────┼────────┼────────┼─────────┼────────┤
│ Req/Sec   │ 350    │ 350    │ 556    │ 616    │ 534.1  │ 75.15   │ 350    │
├───────────┼────────┼────────┼────────┼────────┼────────┼─────────┼────────┤
│ Bytes/Sec │ 442 kB │ 442 kB │ 701 kB │ 777 kB │ 673 kB │ 94.7 kB │ 441 kB │
└───────────┴────────┴────────┴────────┴────────┴────────┴─────────┴────────┘
Req/Bytes counts sampled once per second.
# of samples: 10
5k requests in 10.02s, 6.74 MB read
Running 10s test @ http://localhost:3000/vitruvius
10 connections
┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
│ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
│ Latency │ 13 ms │ 18 ms │ 39 ms │ 43 ms │ 20.21 ms │ 7.11 ms │ 80 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min     │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Req/Sec   │ 331     │ 331     │ 493     │ 538     │ 482.3   │ 57.01  │ 331     │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Bytes/Sec │ 3.25 MB │ 3.25 MB │ 4.85 MB │ 5.29 MB │ 4.74 MB │ 560 kB │ 3.25 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘
Req/Bytes counts sampled once per second.
# of samples: 10
5k requests in 10.02s, 47.4 MB read

Motivation and Context

It improves requests performance

How Has This Been Tested?

Types of Changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation (adding or updating documentation)
  • Dependency update
  • Security update

Checklist:

  • My change requires a change to the documentation and I have updated the documentation accordingly.
  • These changes should be applied to a maintenance branch.
  • This change requires cross browser checks.
  • Performance tests should be ran against the server prior to merging.
  • This change impacts caching for client browsers.
  • This change impacts HTTP headers.
  • This change adds additional environment variable requirements for One App users.
  • I have added the Apache 2.0 license header to any new files created.

What is the Impact to Developers Using One App?

feat: migrated express to fastify
@github-actions
Copy link
Contributor

github-actions bot commented Dec 5, 2022

Size Change: -2.02 kB (0%)

Total Size: 682 kB

Filename Size Change
./build/app/app.js 164 kB -1.63 kB (-1%)
./build/app/app~vendors.js 388 kB +1.03 kB (0%)
./build/app/service-worker-client.js 7.26 kB -3 B (0%)
./build/app/vendors.js 115 kB -1.43 kB (-1%)
ℹ️ View Unchanged
Filename Size
./build/app/runtime.js 7.07 kB

compressed-size-action

bishnubista
bishnubista previously approved these changes Dec 6, 2022
@giulianok
Copy link
Member Author

Size Change: +8.13 kB (+1%)

Total Size: 689 kB

Filename Size Change
./build/app/app.js 173 kB +7.5 kB (+5%) 🔍
./build/app/app~vendors.js 387 kB +512 B (0%)
./build/app/service-worker-client.js 7.26 kB -3 B (0%)
./build/app/vendors.js 114 kB +115 B (0%)
ℹ️ View Unchanged
Filename Size
./build/app/runtime.js 7.07 kB
compressed-size-action

Just fyi, the bundles are identical, not sure why this diff is showing that, for example, app.js got an increased of 5%

Fastify feature branch

Screen Shot 2022-12-06 at 1 28 36 PM

Report from main branch

Screen Shot 2022-12-06 at 1 12 29 PM

@giulianok giulianok requested a review from bishnubista December 6, 2022 18:30
code-forger
code-forger previously approved these changes Dec 7, 2022
bishnubista
bishnubista previously approved these changes Dec 7, 2022
Copy link
Member

@10xLaCroixDrinker 10xLaCroixDrinker left a comment

Choose a reason for hiding this comment

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

Hold on merging for discussion on testing

@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2023

This pull request is stale because it has been open 30 days with no activity.

@dogpatch626 dogpatch626 dismissed stale reviews from bishnubista and code-forger via 9a8c17e January 17, 2023 21:42
fix: matching headers with existing express output
@@ -115,11 +119,13 @@
"joi": "^17.6.0",
"lean-intl": "^4.2.2",
"matcher": "^4.0.0",
"node-fetch": "^2.6.7",
Copy link
Member

Choose a reason for hiding this comment

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

we already have cross-fetch installed

Suggested change
"node-fetch": "^2.6.7",

Copy link
Member Author

Choose a reason for hiding this comment

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

node-fetch was added in this PR https://github.com/americanexpress/one-app/pull/882/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519. @dogpatch626 do you know if we need it installed and that particular version?

Copy link
Contributor

Choose a reason for hiding this comment

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

yea we use that particular version in multiple repos for testing in particular I believe. installing it was just to replace got with node-fetch.

package.json Outdated
@@ -165,6 +172,7 @@
"eslint-plugin-jest": "^24.7.0",
"eslint-plugin-jest-dom": "^3.9.4",
"expect": "^28.1.1",
"express": "^4.18.2",
Copy link
Member

Choose a reason for hiding this comment

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

Why is this here?

Copy link
Member Author

Choose a reason for hiding this comment

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

right, completely forgot, those are left overs, we do not need them anymore. Also found some others that I just removed

@@ -20,6 +20,7 @@ import { jsx, css } from '@emotion/core';
import styles from './styles.scss';

const HelloMessage = () => (
// eslint-disable-next-line react/no-unknown-property
Copy link
Member

Choose a reason for hiding this comment

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

Can you update the lint config for the prod-sample so we dont need this?

renderProps: {
routes,
components: [() => 'hi'],
// history: browserHistory,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// history: browserHistory,

});

describe('empty frame-ancestors', () => {
test('does not add frame options header', () => {
Copy link
Member

Choose a reason for hiding this comment

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

in the addCacheHeaders.spec.js test file we use it, and here we are using test. We should be consistent

@10xLaCroixDrinker 10xLaCroixDrinker merged commit 85ff3c7 into main Jan 31, 2023
@10xLaCroixDrinker 10xLaCroixDrinker deleted the feature/express-fastify-migration branch January 31, 2023 20:24
giulianok added a commit that referenced this pull request Feb 2, 2023
@giulianok giulianok restored the feature/express-fastify-migration branch February 3, 2023 18:59
@dogpatch626 dogpatch626 deleted the feature/express-fastify-migration branch June 15, 2023 14:13
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants