Memory Leak in Node V12

Found memory leak in node v12.14(not only this version), issues have already been fixed in v12.18.2.

Release notes: 2020-06-30, Version 12.18.2

  • deps: V8: backport fb26d0bb1835 (Matheus Marchini) #33573
    • Fixes memory leak in PrototypeUsers::Add
  • src: use symbol to store AsyncWrap resource (Anna Henningsen) #31745
    • Fixes reported memory leak in #33468

I reproduced this issue locally and here is the heap usage comparison for same code using different node versions.

Aws Sts Assume-Role

aws sts assume-role is very useful for cross-account access. Imaging using dev account for build and testing and assume to prod account for deployment.

To assume a role, your AWS account must be trusted by the role. The trust relationship is defined in the role’s trust policy when the role is created. That trust policy states which accounts are allowed to delegate access to this account’s role.

By default, the temporary security credentials created by AssumeRole last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session. You can provide a value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

To assume a role:

1
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/xaccounts3access --role-session-name s3-access-example

The output of the command contains an access key, secret key, and session token that you can use to authenticate to AWS:

1
2
3
4
5
6
7
8
9
10
11
12
{
"AssumedRoleUser": {
"AssumedRoleId": "AROA3XFRBF535PLBIFPI4:s3-access-example",
"Arn": "arn:aws:sts::123456789012:assumed-role/xaccounts3access/s3-access-example"
},
"Credentials": {
"SecretAccessKey": "9drTJvcXLB89EXAMPLELB8923FB892xMFI",
"SessionToken": "AQoXdzELDDY//////////wEaoAK1wvxJY12r2IrDFT2IvAzTCn3zHoZ7YNtpiQLF0MqZye/qwjzP2iEXAMPLEbw/m3hsj8VBTkPORGvr9jM5sgP+w9IZWZnU+LWhmg+a5fDi2oTGUYcdg9uexQ4mtCHIHfi4citgqZTgco40Yqr4lIlo4V2b2Dyauk0eYFNebHtYlFVgAUj+7Indz3LU0aTWk1WKIjHmmMCIoTkyYp/k7kUG7moeEYKSitwQIi6Gjn+nyzM+PtoA3685ixzv0R7i5rjQi0YE0lf1oeie3bDiNHncmzosRM6SFiPzSvp6h/32xQuZsjcypmwsPSDtTPYcs0+YN/8BRi2/IcrxSpnWEXAMPLEXSDFTAQAM6Dl9zR0tXoybnlrZIwMLlMi1Kcgo5OytwU=",
"Expiration": "2016-03-15T00:05:07Z",
"AccessKeyId": "ASIAJEXAMPLEXEG2JICEA"
}
}

Used in build bash scripts:

1
2
3
4
5
6
7
8
assume_role() {
local creds
$(aws sts assume-role --role-arn "$1" --role-session-name your-session-name --output text --query 'Credentials | join(``, [`"export AWS_ACCESS_KEY_ID="`,AccessKeyId,`" AWS_SECRET_ACCESS_KEY="`,SecretAccessKey,`" AWS_SESSION_TOKEN="`,SessionToken,`\n`])')
}

if [ -n "${ASSUME_ROLE:-}" ]; then
assume_role "$ASSUME_ROLE"
fi

https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role.html

Use Async or Promise in AWS Lambda Handler

In AWS lambda, before node.js runtime 8.10, although you can use promise across all your code, but in top handler, you must follow the below callback pattern. async/await is not supported in handler, even in other functions you must use something like babel to transform your code before deploy.

Previous callback pattern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const api = require('something');

exports.handler = (event, context, callback) => {
const getSomthingPromise = api.getSomthing(event);
getSomthingPromise.then(
data => {
callback(null, data);
},
err => {
console.log(err);
callback(err);
}
);
};

With the new Node.js 8.10, you can use promise or async/await pattern in handler, just like normal node.js function. And you don’t need to pass context and callback parameters, only event.

Use async/await

for sync value without await:

1
2
3
4
5
6
exports.handler = async (event) => {
return {
statusCode: 200,
body: 'ok'
}
}

for async value with await:

1
2
3
4
5
6
7
8
9
const api = require('something');

exports.handler = async (event) => {
const data = await api.getSomthing(event);
return {
statusCode: 200,
body: JSON.stringify({ data })
};
};

Use Promise

for sync value wrap in Promise:

1
2
3
4
5
6
exports.handler = (event) => {
return Promise.resolve({
statusCode: 200,
body: 'ok'
})
};

for async:

you can directly return it, but I don’t recommend this way

1
2
3
4
5
const api = require('something');

exports.handler = (event) => {
return api.getSomthing(event);
};

It’s better start from Promise.resolve():

1
2
3
4
exports.handler = (event) => {
return Promise.resolve(event)
.then(api.getSomthing);
};

Summary

To use async or Promise, it’s up to your choice. But I’m sure either way is easier than the previous callback pattern. Also to mention again, async/await is actually a syntactic sugar for promise in js.

Ref:
https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/

Use Prettier to Format Your Code, Automatically, for All Your Team

As a developer, I highly recommend to use prettier in your editor. And today I’d like to go a step further, force and automate code formatting for all your team. No need to discuss the code style any more, don’t waste time on the arguments about space or tab, whether or not add a new line. And it’s much neat for code diff and review.

It’s very easy, only 2 steps.

  1. Install pretty-quick and husky. pretty-quick runs prettier on your changed files and husky gives the hook for precommit.
1
yarn add pretty-quick husky --dev
  1. add this script to your package.json:
1
2
3
4
5
{
"scripts": {
"precommit": "pretty-quick --staged"
}
}

Now every time when any team member commit, the changed files will be prettified.