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

feat: enable asyncLocalStorage by default #251

Merged
merged 4 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [8, 10, 12, 14, 16]
node-version: [8, 10, 12, 14, 16, 18]
os: [ubuntu-latest, windows-latest, macos-latest]

steps:
Expand Down
148 changes: 148 additions & 0 deletions benchmark/middleware/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,151 @@ Transfer/sec: 6.01MB
```

![](https://user-images.githubusercontent.com/985607/32474444-2f4b7cde-c332-11e7-923f-8dfb709a7a24.png)

### 2022-12-06

Enable asyncLocalStorage

```
v18.12.1
server started at 7001
------- generator middleware -------
["generator middleware #1","generator middleware #2","generator middleware #3","generator middleware #4","generator middleware #5","generator middleware #6","generator middleware #7","generator middleware #8","generator middleware #9","generator middleware #10","generator middleware #11","generator middleware #12","generator middleware #13","generator middleware #14","generator middleware #15","generator middleware #16","generator middleware #17","generator middleware #18","generator middleware #19","generator middleware #20"]
Running 10s test @ http://127.0.0.1:7001/generator
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.42ms 584.46us 12.20ms 94.43%
Req/Sec 2.50k 601.24 18.36k 97.63%
198950 requests in 10.10s, 153.00MB read
Requests/sec: 19699.09
Transfer/sec: 15.15MB
------- async middleware -------
["async middleware #1","async middleware #2","async middleware #3","async middleware #4","async middleware #5","async middleware #6","async middleware #7","async middleware #8","async middleware #9","async middleware #10","async middleware #11","async middleware #12","async middleware #13","async middleware #14","async middleware #15","async middleware #16","async middleware #17","async middleware #18","async middleware #19","async middleware #20"]
Running 10s test @ http://127.0.0.1:7001/async
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.97ms 1.58ms 43.26ms 96.10%
Req/Sec 3.23k 0.86k 24.84k 95.38%
257959 requests in 10.10s, 179.02MB read
Requests/sec: 25533.50
Transfer/sec: 17.72MB

v16.18.1
server started at 7001
------- generator middleware -------
["generator middleware #1","generator middleware #2","generator middleware #3","generator middleware #4","generator middleware #5","generator middleware #6","generator middleware #7","generator middleware #8","generator middleware #9","generator middleware #10","generator middleware #11","generator middleware #12","generator middleware #13","generator middleware #14","generator middleware #15","generator middleware #16","generator middleware #17","generator middleware #18","generator middleware #19","generator middleware #20"]
Running 10s test @ http://127.0.0.1:7001/generator
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.53ms 1.21ms 36.34ms 93.77%
Req/Sec 2.44k 372.60 7.16k 91.78%
194905 requests in 10.10s, 149.87MB read
Requests/sec: 19288.29
Transfer/sec: 14.83MB
------- async middleware -------
["async middleware #1","async middleware #2","async middleware #3","async middleware #4","async middleware #5","async middleware #6","async middleware #7","async middleware #8","async middleware #9","async middleware #10","async middleware #11","async middleware #12","async middleware #13","async middleware #14","async middleware #15","async middleware #16","async middleware #17","async middleware #18","async middleware #19","async middleware #20"]
Running 10s test @ http://127.0.0.1:7001/async
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.76ms 405.33us 10.08ms 89.00%
Req/Sec 3.43k 264.17 5.94k 85.09%
275242 requests in 10.10s, 191.08MB read
Requests/sec: 27242.76
Transfer/sec: 18.91MB

v14.21.1
server started at 7001
------- generator middleware -------
["generator middleware #1","generator middleware #2","generator middleware #3","generator middleware #4","generator middleware #5","generator middleware #6","generator middleware #7","generator middleware #8","generator middleware #9","generator middleware #10","generator middleware #11","generator middleware #12","generator middleware #13","generator middleware #14","generator middleware #15","generator middleware #16","generator middleware #17","generator middleware #18","generator middleware #19","generator middleware #20"]
Running 10s test @ http://127.0.0.1:7001/generator
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 4.16ms 2.46ms 39.16ms 91.43%
Req/Sec 1.55k 349.54 1.92k 84.88%
123307 requests in 10.04s, 94.43MB read
Requests/sec: 12280.55
Transfer/sec: 9.40MB
------- async middleware -------
["async middleware #1","async middleware #2","async middleware #3","async middleware #4","async middleware #5","async middleware #6","async middleware #7","async middleware #8","async middleware #9","async middleware #10","async middleware #11","async middleware #12","async middleware #13","async middleware #14","async middleware #15","async middleware #16","async middleware #17","async middleware #18","async middleware #19","async middleware #20"]
Running 10s test @ http://127.0.0.1:7001/async
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.88ms 1.38ms 24.43ms 93.97%
Req/Sec 2.19k 283.92 2.94k 85.25%
174192 requests in 10.01s, 120.54MB read
Requests/sec: 17395.81
Transfer/sec: 12.04MB

v12.22.12
Copy link
Member Author

Choose a reason for hiding this comment

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

v12 性能是真的下降很多。

Copy link
Member

Choose a reason for hiding this comment

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

毕竟那个版本还没优化 async hook 吧,反正不是我们最小支持版本了

Copy link
Member Author

Choose a reason for hiding this comment

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

毕竟那个版本还没优化 async hook 吧,反正不是我们最小支持版本了

春节之后给 egg-core 发布一个 major 版本,只支持 node 14+

server started at 7001
------- generator middleware -------
["generator middleware #1","generator middleware #2","generator middleware #3","generator middleware #4","generator middleware #5","generator middleware #6","generator middleware #7","generator middleware #8","generator middleware #9","generator middleware #10","generator middleware #11","generator middleware #12","generator middleware #13","generator middleware #14","generator middleware #15","generator middleware #16","generator middleware #17","generator middleware #18","generator middleware #19","generator middleware #20"]
Running 10s test @ http://127.0.0.1:7001/generator
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 11.04ms 9.39ms 75.99ms 91.60%
Req/Sec 638.74 167.21 0.90k 63.25%
50990 requests in 10.04s, 38.43MB read
Requests/sec: 5078.85
Transfer/sec: 3.83MB
------- async middleware -------
["async middleware #1","async middleware #2","async middleware #3","async middleware #4","async middleware #5","async middleware #6","async middleware #7","async middleware #8","async middleware #9","async middleware #10","async middleware #11","async middleware #12","async middleware #13","async middleware #14","async middleware #15","async middleware #16","async middleware #17","async middleware #18","async middleware #19","async middleware #20"]
Running 10s test @ http://127.0.0.1:7001/async
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 7.45ms 7.68ms 69.86ms 93.04%
Req/Sec 1.00k 195.80 1.26k 74.50%
80059 requests in 10.03s, 54.83MB read
Requests/sec: 7981.39
Transfer/sec: 5.47MB
```

Disable asyncLocalStorage

```
v18.12.1
server started at 7001
------- generator middleware -------
["generator middleware #1","generator middleware #2","generator middleware #3","generator middleware #4","generator middleware #5","generator middleware #6","generator middleware #7","generator middleware #8","generator middleware #9","generator middleware #10","generator middleware #11","generator middleware #12","generator middleware #13","generator middleware #14","generator middleware #15","generator middleware #16","generator middleware #17","generator middleware #18","generator middleware #19","generator middleware #20"]
Running 10s test @ http://127.0.0.1:7001/generator
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.22ms 1.18ms 38.70ms 93.88%
Req/Sec 2.79k 361.32 3.27k 85.50%
222356 requests in 10.01s, 171.13MB read
Requests/sec: 22208.19
Transfer/sec: 17.09MB
------- async middleware -------
["async middleware #1","async middleware #2","async middleware #3","async middleware #4","async middleware #5","async middleware #6","async middleware #7","async middleware #8","async middleware #9","async middleware #10","async middleware #11","async middleware #12","async middleware #13","async middleware #14","async middleware #15","async middleware #16","async middleware #17","async middleware #18","async middleware #19","async middleware #20"]
Running 10s test @ http://127.0.0.1:7001/async
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.71ms 0.98ms 33.63ms 94.19%
Req/Sec 3.60k 511.38 10.65k 91.28%
288119 requests in 10.10s, 200.07MB read
Requests/sec: 28513.37
Transfer/sec: 19.80MB

v8.17.0
server started at 7001
------- generator middleware -------
["generator middleware #1","generator middleware #2","generator middleware #3","generator middleware #4","generator middleware #5","generator middleware #6","generator middleware #7","generator middleware #8","generator middleware #9","generator middleware #10","generator middleware #11","generator middleware #12","generator middleware #13","generator middleware #14","generator middleware #15","generator middleware #16","generator middleware #17","generator middleware #18","generator middleware #19","generator middleware #20"]
Running 10s test @ http://127.0.0.1:7001/generator
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 4.10ms 2.11ms 29.73ms 93.47%
Req/Sec 1.53k 241.05 3.74k 84.43%
122526 requests in 10.11s, 91.14MB read
Requests/sec: 12123.93
Transfer/sec: 9.02MB
------- async middleware -------
["async middleware #1","async middleware #2","async middleware #3","async middleware #4","async middleware #5","async middleware #6","async middleware #7","async middleware #8","async middleware #9","async middleware #10","async middleware #11","async middleware #12","async middleware #13","async middleware #14","async middleware #15","async middleware #16","async middleware #17","async middleware #18","async middleware #19","async middleware #20"]
Running 10s test @ http://127.0.0.1:7001/async
8 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.66ms 4.33ms 86.07ms 96.97%
Req/Sec 1.89k 296.76 2.24k 86.50%
151007 requests in 10.04s, 101.04MB read
Requests/sec: 15046.06
Transfer/sec: 10.07MB
```
5 changes: 4 additions & 1 deletion lib/egg.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const utils = require('./utils');
const Router = require('@eggjs/router').EggRouter;
const Timing = require('./utils/timing');
const Lifecycle = require('./lifecycle');
const enableAsyncLocalStorage = !!require('async_hooks').AsyncLocalStorage;

const DEPRECATE = Symbol('EggCore#deprecate');
const ROUTER = Symbol('EggCore#router');
Expand All @@ -37,7 +38,9 @@ class EggCore extends KoaApplication {
assert(fs.statSync(options.baseDir).isDirectory(), `Directory ${options.baseDir} is not a directory`);
assert(options.type === 'application' || options.type === 'agent', 'options.type should be application or agent');

super();
// enable asyncLocalStorage by default
// https://github.com/koajs/koa/pull/1721
super({ asyncLocalStorage: enableAsyncLocalStorage });

this.timing = new Timing();

Expand Down
4 changes: 2 additions & 2 deletions lib/lifecycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const getReady = require('get-ready');
const { Ready } = require('ready-callback');
const { EventEmitter } = require('events');
const debug = require('debug')('egg-core:lifecycle');
const utils = require('./utils');

const INIT = Symbol('Lifycycle#init');
const INIT_READY = Symbol('Lifecycle#initReady');
const DELEGATE_READY_EVENT = Symbol('Lifecycle#delegateReadyEvent');
Expand All @@ -15,8 +17,6 @@ const IS_CLOSED = Symbol('Lifecycle#isClosed');
const BOOT_HOOKS = Symbol('Lifecycle#bootHooks');
const BOOTS = Symbol('Lifecycle#boots');

const utils = require('./utils');

class Lifecycle extends EventEmitter {

/**
Expand Down
1 change: 0 additions & 1 deletion lib/utils/timing.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const assert = require('assert');
const MAP = Symbol('Timing#map');
const LIST = Symbol('Timing#list');


class Timing {

constructor() {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},
"ci": {
"type": "github",
"version": "8, 10, 12, 14, 16",
"version": "8, 10, 12, 14, 16, 18",
"afterScript": "after_success:\n - npminstall codecov && codecov --disable=gcov",
"license": {
"year": 2016
Expand Down Expand Up @@ -73,7 +73,7 @@
"get-ready": "^2.0.1",
"globby": "^10.0.2",
"is-type-of": "^1.2.1",
"koa": "^2.7.0",
"koa": "^2.14.0",
"koa-convert": "^1.2.0",
"node-homedir": "^1.1.1",
"ready-callback": "^2.1.0",
Expand Down
31 changes: 31 additions & 0 deletions test/asyncLocalStorage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const assert = require('assert');
const path = require('path');
const request = require('supertest');
const enableAsyncLocalStorage = !!require('async_hooks').AsyncLocalStorage;
const EggApplication = require('./fixtures/egg').Application;

describe('test/asyncLocalStorage.test.js', () => {
let app;
before(() => {
app = new EggApplication({
baseDir: path.join(__dirname, 'fixtures/session-cache-app'),
type: 'application',
});
app.loader.loadAll();
});

it('should start app with asyncLocalStorage = true by default', async () => {
assert(app.currentContext === undefined);
const res = await request(app.callback())
.get('/');
assert(res.status === 200);
console.log(res.body);
assert(res.body.sessionId === 'mock-session-id-123');
if (enableAsyncLocalStorage) {
assert(res.body.traceId);
}
assert(app.currentContext === undefined);
});
});
38 changes: 20 additions & 18 deletions test/egg.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ describe('test/egg.test.js', () => {
after(() => app && app.close());

describe('app', () => {
it('should get timing', function* () {
it('should get timing', async () => {
app = utils.createApp('timing');
app.loader.loadPlugin();
app.loader.loadConfig();
Expand All @@ -477,10 +477,10 @@ describe('test/egg.test.js', () => {
app.loader.loadMiddleware();
app.loader.loadController();
app.loader.loadRouter();
yield app.ready();
await app.ready();

const json = app.timing.toJSON();
assert(json.length === 27);
assert(json.length === 28);

assert(json[1].name === 'Application Start');
assert(json[1].end - json[1].start === json[1].duration);
Expand All @@ -500,30 +500,32 @@ describe('test/egg.test.js', () => {

// loadCustomApp
assert(json[11].name === 'Load app.js');
assert(json[12].name === 'Require(6) app.js');
assert(json[13].name === 'Before Start in app.js:6:9');
assert(json[14].name === 'Before Start in mock Block');
assert(json[15].name === 'readyCallback in mockReadyCallbackWithoutFunction');
// test/fixtures/egg/node_modules/session/app.js
assert(json[12].name.startsWith('Require(6) '));
assert(json[13].name === 'Require(7) app.js');
assert(json[14].name === 'Before Start in app.js:6:9');
assert(json[15].name === 'Before Start in mock Block');
assert(json[16].name === 'readyCallback in mockReadyCallbackWithoutFunction');

assert(json[16].name === 'Load "proxy" to Context');
assert(json[17].name === 'Load Controller');
assert(json[18].name === 'Load "controller" to Application');
assert(json[17].name === 'Load "proxy" to Context');
assert(json[18].name === 'Load Controller');
assert(json[19].name === 'Load "controller" to Application');

// loadService
assert(json[19].name === 'Load Service');
assert(json[20].name === 'Load "service" to Context');
assert(json[20].name === 'Load Service');
assert(json[21].name === 'Load "service" to Context');

// loadMiddleware
assert(json[21].name === 'Load Middleware');
assert(json[22].name === 'Load "middlewares" to Application');
assert(json[22].name === 'Load Middleware');
assert(json[23].name === 'Load "middlewares" to Application');

// loadController
assert(json[23].name === 'Load Controller');
assert(json[24].name === 'Load "controller" to Application');
assert(json[24].name === 'Load Controller');
assert(json[25].name === 'Load "controller" to Application');

// loadRouter
assert(json[25].name === 'Load Router');
assert(json[26].name === 'Require(7) app/router.js');
assert(json[26].name === 'Load Router');
assert(json[27].name === 'Require(8) app/router.js');
});
});

Expand Down
1 change: 1 addition & 0 deletions test/fixtures/egg/app/middleware/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

module.exports = function() {
return (ctx, next) => {
ctx.traceId = `trace:${Date.now()}`;
if (ctx.path === '/status') {
ctx.body = 'egg status';
return;
Expand Down
13 changes: 13 additions & 0 deletions test/fixtures/egg/node_modules/session/app.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions test/fixtures/session-cache-app/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = async ctx => {
ctx.body = await ctx.app.sessionCache.getSessionById('mock-session-id-123');
};
3 changes: 3 additions & 0 deletions test/fixtures/session-cache-app/app/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = app => {
app.get('/', 'home');
};
3 changes: 3 additions & 0 deletions test/fixtures/session-cache-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "session-cache-app"
}
8 changes: 7 additions & 1 deletion test/loader/mixin/load_middleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const path = require('path');
const assert = require('assert');
const request = require('supertest');
const enableAsyncLocalStorage = !!require('async_hooks').AsyncLocalStorage;
const utils = require('../../utils');

describe('test/loader/mixin/load_middleware.test.js', function() {
Expand Down Expand Up @@ -37,7 +38,12 @@ describe('test/loader/mixin/load_middleware.test.js', function() {
for (const mw of app.middleware) {
assert(typeof mw === 'function');
}
assert(Object.keys(app.middleware).length === 3);
if (enableAsyncLocalStorage) {
// the first middleware is asyncCtxStorage
assert(Object.keys(app.middleware).length === 4);
} else {
assert(Object.keys(app.middleware).length === 3);
}
});

it('should override middlewares of plugin by framework', async () => {
Expand Down