@studio/lambda
Advanced tools
+12
-7
| { | ||
| "name": "@studio/lambda", | ||
| "version": "5.0.1", | ||
| "version": "5.0.2", | ||
| "description": "JavaScript Studio lambda execution environment", | ||
@@ -21,3 +21,3 @@ "author": "Maximilian Antoni <max@javascript.studio>", | ||
| "prettier:write": "prettier --write '**/*.{js,json,md}'", | ||
| "prepare": "husky install" | ||
| "prepare": "husky" | ||
| }, | ||
@@ -28,3 +28,3 @@ "eslintConfig": { | ||
| "dependencies": { | ||
| "@studio/log": "^2.0.0", | ||
| "@studio/log": "^2.1.3", | ||
| "@studio/ndjson": "^2.1.0" | ||
@@ -37,8 +37,13 @@ }, | ||
| "eslint": "^8.56.0", | ||
| "husky": "^8.0.3", | ||
| "lint-staged": "^15.2.0", | ||
| "mocha": "^10.2.0", | ||
| "prettier": "^3.1.1" | ||
| "husky": "^9.1.5", | ||
| "lint-staged": "^15.2.9", | ||
| "mocha": "^10.7.3", | ||
| "prettier": "^3.3.3" | ||
| }, | ||
| "files": [ | ||
| "lib", | ||
| "LICENSE", | ||
| "README.md" | ||
| ], | ||
| "license": "MIT" | ||
| } |
| name: Build | ||
| on: [push] | ||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
| strategy: | ||
| matrix: | ||
| node-version: ['18.x', '20.x'] | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v3 | ||
| - name: Use Node.js ${{ matrix.node-version }} | ||
| uses: actions/setup-node@v3 | ||
| with: | ||
| node-version: ${{ matrix.node-version }} | ||
| cache: 'npm' | ||
| - name: Install | ||
| run: npm ci | ||
| - name: Lint | ||
| if: matrix.node-version == '20.x' | ||
| run: npm run lint | ||
| - name: Prettier | ||
| if: matrix.node-version == '20.x' | ||
| run: npm run prettier:check | ||
| - name: Test | ||
| run: npm test |
Sorry, the diff of this file is not supported yet
| 'use strict'; | ||
| module.exports = { | ||
| '*.js': 'eslint --fix', | ||
| '*.{js,md}': 'prettier --write' | ||
| }; |
Sorry, the diff of this file is not supported yet
| { | ||
| "singleQuote": true, | ||
| "trailingComma": "none" | ||
| } |
-322
| # Changes | ||
| ## 5.0.1 | ||
| - 🐛 [`446db5c`](https://github.com/javascript-studio/studio-lambda/commit/446db5c1925c71c71a9d46b8a2594483fe4dab25) | ||
| Fix max idle overtaking lambda timeout | ||
| - 📚 [`16953a0`](https://github.com/javascript-studio/studio-lambda/commit/16953a0c3d91773c58aa26930e985217010ce962) | ||
| Add missing documentation for timeout option | ||
| - 📚 [`e582183`](https://github.com/javascript-studio/studio-lambda/commit/e582183c319d65dd66abe5e1a7ee007c6184c541) | ||
| Remove bad link to apex | ||
| _Released by [Maximilian Antoni](https://github.com/mantoni) on 2024-08-28._ | ||
| ## 5.0.0 | ||
| - [`50359f9`](https://github.com/javascript-studio/studio-lambda/commit/50359f942e13f5ff4f2f958ce66ecf4d119c69f1) | ||
| Use husky and lint-staged | ||
| - [`7c72184`](https://github.com/javascript-studio/studio-lambda/commit/7c721842ffe07ca9dd2ae7507b24267cdbbf1dfb) | ||
| Drop node 16 | ||
| - [`abb5df7`](https://github.com/javascript-studio/studio-lambda/commit/abb5df7ab3400ad5f41511425c3c0c1a13d302a0) | ||
| Rename master to main | ||
| - [`d0be735`](https://github.com/javascript-studio/studio-lambda/commit/d0be735b756ad7189a9abcabf4e7cf09a50441ee) | ||
| State MIT license in package.json | ||
| - [`af1f621`](https://github.com/javascript-studio/studio-lambda/commit/af1f6217d7cdd75ad23e12a1abd16469a867eccd) | ||
| Add LICENSE | ||
| _Released by [Maximilian Antoni](https://github.com/mantoni) on 2024-01-17._ | ||
| ## 4.0.1 | ||
| - ✨ [`cca2e48`](https://github.com/javascript-studio/studio-lambda/commit/cca2e48693b8b900aa40b296b8ee4bb276be470b) | ||
| Support node 20 and update GitHub action | ||
| - ✨ [`d64d9ff`](https://github.com/javascript-studio/studio-lambda/commit/d64d9ff20a4f8fec8eb72b49ec0aeef3d75e4d42) | ||
| Upgrade prettier to v3 | ||
| - ✨ [`2670491`](https://github.com/javascript-studio/studio-lambda/commit/267049180cead33e746b75e7c88098b22613a68a) | ||
| Update eslint config and eslint | ||
| - ✨ [`c27072b`](https://github.com/javascript-studio/studio-lambda/commit/c27072b6a51d755f3c5fec354199a7638f2c0fbf) | ||
| Update Studio ndjson | ||
| - ✨ [`06c894f`](https://github.com/javascript-studio/studio-lambda/commit/06c894f05c291feb730a86cea9c730bd7312e987) | ||
| Upgrade Studio Changes | ||
| - ✨ [`4e929c7`](https://github.com/javascript-studio/studio-lambda/commit/4e929c703cd47ab1e1ff8f37145a62c9f459260b) | ||
| Upgrade @sinonjs/referee-sinon | ||
| _Released by [Maximilian Antoni](https://github.com/mantoni) on 2024-01-11._ | ||
| ## 4.0.0 | ||
| - 💥 [`8be1398`](https://github.com/javascript-studio/studio-lambda/commit/8be1398865ee2b415d8fd04436068d495ac586ea) | ||
| Require node 16 | ||
| - 💥 [`496cc52`](https://github.com/javascript-studio/studio-lambda/commit/496cc525838552e0284f740d07d9c5620233366e) | ||
| Use dynamic import to support loading es modules | ||
| - 💥 [`d458059`](https://github.com/javascript-studio/studio-lambda/commit/d4580593c68ef845a236c03a7be02a6bffbb181a) | ||
| Change generic destroy error code to `E_FAILED` | ||
| - 🛡 [`8a6a3b3`](https://github.com/javascript-studio/studio-lambda/commit/8a6a3b35a5d28e21502cdbad8140039b8341196f) | ||
| npm audit | ||
| - ✨ [`6814ed2`](https://github.com/javascript-studio/studio-lambda/commit/6814ed26f83fdec1807e14b42d2a5c8a12afe973) | ||
| Update Studio Changes | ||
| - ✨ [`0d942b9`](https://github.com/javascript-studio/studio-lambda/commit/0d942b9a8733808958dfec9d6f2071901dc8b597) | ||
| Upgrade referee-sinon | ||
| - ✨ [`673cc02`](https://github.com/javascript-studio/studio-lambda/commit/673cc0266bdaf961fd8d688d96f0bb6b0221f469) | ||
| Update prettier | ||
| - ✨ [`5c264ff`](https://github.com/javascript-studio/studio-lambda/commit/5c264ff5560fc7eb4b518f8f3dfd455f9438d6da) | ||
| Upgrade mocha | ||
| - ✨ [`bf9897b`](https://github.com/javascript-studio/studio-lambda/commit/bf9897bc9a2317d3224b0cf4a0abff5e82872c0c) | ||
| Upgrade eslint-config and eslint | ||
| _Released by [Maximilian Antoni](https://github.com/mantoni) on 2023-01-19._ | ||
| ## 3.0.2 | ||
| - 🐛 [`5b7e59e`](https://github.com/javascript-studio/studio-lambda/commit/5b7e59e36d5b041b729ebc41e1b6edf40ad3d390) | ||
| Fix region and account config via env | ||
| _Released by [Maximilian Antoni](https://github.com/mantoni) on 2021-06-23._ | ||
| ## 3.0.1 | ||
| - 🐛 [`e1be0d4`](https://github.com/javascript-studio/studio-lambda/commit/e1be0d43cc69645cd7f9a10b7a51d3358af96b28) | ||
| Handler `JSON.stringify` error in lambda response | ||
| - ✨ [`526574b`](https://github.com/javascript-studio/studio-lambda/commit/526574b5dbf616747079a012f5075384b25d92ab) | ||
| Upgrade @sinonjs/referee-sinon to latest (Morgan Roderick) | ||
| - ✨ [`2f25018`](https://github.com/javascript-studio/studio-lambda/commit/2f25018dec371373b33c8245549135cb3c79aeb9) | ||
| Set required node version in package-lock.json (Morgan Roderick) | ||
| _Released by [Maximilian Antoni](https://github.com/mantoni) on 2021-05-21._ | ||
| ## 3.0.0 | ||
| - 💥 [`b5a53ad`](https://github.com/javascript-studio/studio-lambda/commit/b5a53ad96c6e915d35015923c5055895c84d7352) | ||
| Require node 12 | ||
| - 🍏 [`21b2d2c`](https://github.com/javascript-studio/studio-lambda/commit/21b2d2c4b5b6551935335f7df5d2c36e9306add7) | ||
| Return promise in lambda.invoke if no callback is given | ||
| - 🍏 [`c37577a`](https://github.com/javascript-studio/studio-lambda/commit/c37577a4beee285f3c6543d30b8b8fa323a0069b) | ||
| Support async lambda functions | ||
| - 📚 [`4de3f74`](https://github.com/javascript-studio/studio-lambda/commit/4de3f74669cf682d0bb962e25416b0d4d1611535) | ||
| Document usage with async await | ||
| - 🐛 [`2111a8f`](https://github.com/javascript-studio/studio-lambda/commit/2111a8f14f153c703ba2ce8989e56b08c7c4f07d) | ||
| Fix error handling if lambda throws while launching | ||
| - ✨ [`957d2e6`](https://github.com/javascript-studio/studio-lambda/commit/957d2e6f7b78fee49db17405cebaf320d049ed71) | ||
| Avoid else by returning early | ||
| - ✨ [`e6879f2`](https://github.com/javascript-studio/studio-lambda/commit/e6879f2575c639d9b3feb1915062a73e1c935169) | ||
| Configure GitHub actions | ||
| - ✨ [`64de260`](https://github.com/javascript-studio/studio-lambda/commit/64de2605cc4875bd1a66cb067a2f066e6ae8977c) | ||
| Run lint, test and prettier checks separately | ||
| - ✨ [`b9db826`](https://github.com/javascript-studio/studio-lambda/commit/b9db8264ebc97c92e21b55489e6015fe90394d6d) | ||
| Update Studio Changes | ||
| - ✨ [`0af1d4e`](https://github.com/javascript-studio/studio-lambda/commit/0af1d4e3005cfe863af46b770cfc9d7502738238) | ||
| Upgrade referee-sinon to latest | ||
| - ✨ [`f2000dd`](https://github.com/javascript-studio/studio-lambda/commit/f2000dd28b2ca00a987c1404034ad5b687b02ad0) | ||
| Upgrade mocha to latest | ||
| - ✨ [`c466a9d`](https://github.com/javascript-studio/studio-lambda/commit/c466a9de0e8954498fe9ef537450db0b891e222e) | ||
| Setup prettier | ||
| - ✨ [`e0469bb`](https://github.com/javascript-studio/studio-lambda/commit/e0469bb7d7514d208d67a5de9c1729f71c8cb92b) | ||
| Upgrade eslint and eslint-config | ||
| - ✨ [`94c71c6`](https://github.com/javascript-studio/studio-lambda/commit/94c71c6ce1338604b61312731dddc06036317de5) | ||
| Use npm 7 | ||
| - ✨ [`b121728`](https://github.com/javascript-studio/studio-lambda/commit/b121728669ce120cb737ea750e1a739170ceac70) | ||
| Add .gitignore | ||
| - ✨ [`883ba54`](https://github.com/javascript-studio/studio-lambda/commit/883ba544640776b0d24d6adafc1fe449dfe2d56e) | ||
| Fix memory limit tests for node 12 | ||
| - ✨ [`0914a38`](https://github.com/javascript-studio/studio-lambda/commit/0914a384b6afcfc3c92e977ee3779347cc6e15ab) | ||
| Upgrade referee-sinon to v6 | ||
| - ✨ [`eb41ede`](https://github.com/javascript-studio/studio-lambda/commit/eb41ede3c2e0abae743d7412c455212b03ccc8b7) | ||
| Upgrade Studio Changes to v2 | ||
| - ✨ [`570c069`](https://github.com/javascript-studio/studio-lambda/commit/570c069af8cddb1cb65d6ec345b3f17ba9d21384) | ||
| Make eslint-config a dev dependency | ||
| _Released by [Maximilian Antoni](https://github.com/mantoni) on 2021-04-21._ | ||
| ## 2.0.2 | ||
| - 🐛 [`6a70c3c`](https://github.com/javascript-studio/studio-lambda/commit/6a70c3cae4640e68d6dd62196aeac5bfaaf62737) | ||
| Revert "Do not prepend forwarded log namespace with name" | ||
| > This reverts commit 7082da34f64146db43402d40835bfb2ffbb934f7. | ||
| ## 2.0.1 | ||
| - 🐛 [`7082da3`](https://github.com/javascript-studio/studio-lambda/commit/7082da34f64146db43402d40835bfb2ffbb934f7) | ||
| Do not prepend forwarded log namespace with name | ||
| ## 2.0.0 | ||
| - 💥 [`82e917a`](https://github.com/javascript-studio/studio-lambda/commit/82e917a83d8536e778ffa18aa461c301d5d656e5) | ||
| __BREAKING:__ Upgrade Studio Log to v2 | ||
| - ✨ [`e0669ea`](https://github.com/javascript-studio/studio-lambda/commit/e0669ea81256c489608fc43c6d8304a5d28293af) | ||
| Use Sinon + Referee and use Sinon default sandbox | ||
| - 📚 [`8362816`](https://github.com/javascript-studio/studio-lambda/commit/83628163b14ca0cd937c8ee6ca01fb3b27c36ae0) | ||
| Add commit links with `--commits` | ||
| ## 1.14.1 | ||
| - 🐛 Pass error cause in logs through to lambda logger | ||
| ## 1.14.0 | ||
| - 🍏 Implement more AWS environment variables for lambda functions | ||
| - 🍏 Change log topic for new lambdas from "launch" to "spawn" | ||
| - ✨ Add tests for AWS_REGION and AWS_PROFILE environment variables | ||
| - ✨ Refactor setting `getRemainingTimeInMillis` on context | ||
| ## 1.13.0 | ||
| - 🍏 Add `shutdown` and `stats` APIs | ||
| - 🐛 Improve lambda function error handling | ||
| - 🐛 Handle ndjson transform errors | ||
| ## 1.12.0 | ||
| - 🍏 Use configured memory and improve process exit handling | ||
| ## 1.11.1 | ||
| - 🐛 Improve generated `awsRequestId` | ||
| ## 1.11.0 | ||
| - 🍏 Add support for `functionName`. | ||
| - 🍏 Add support for `awsRequestId`. | ||
| - 🍏 Add support for `memoryLimitInMB`. | ||
| - 🍏 Add support for `getRemainingTimeInMillis()`. | ||
| - 🐛 Build the function ARN within the Lambda function instead of injecting it. | ||
| The `STUDIO_AWS_ACCOUNT` environment variable was not picket up correctly. | ||
| ## 1.10.1 | ||
| - ✨ Use `@studio/ndjson` to parse log output from Lambdas | ||
| ## 1.10.0 | ||
| - ⚠️ Remove hack to filter log data | ||
| > Log data should be filtered where it's created. With the new | ||
| > `@studio/log-x` module and the updated `@studio/wrap` this hack can be | ||
| > removed. | ||
| - ✨ Add `package-lock.json` | ||
| ## 1.9.1 | ||
| - 🐛 Add `invokedFunctionArn` to given context if missing | ||
| ## 1.9.0 | ||
| - 🍏 Generate `invokedFunctionArn` in default context | ||
| - 📚 Use upper case `Lambda` module name in examples | ||
| ## 1.8.2 | ||
| - 🐛 Fix entries cleanup in kill handler | ||
| > The entries array is not necessarily cleaned up in reverse insertion | ||
| > order. With this patch, the kill handler does not expect the entry at a | ||
| > fixed position, but queries the entry to remove by ID instead. | ||
| ## 1.8.1 | ||
| - 🐛 Fail on missing environment variables | ||
| > - Throw an error if a variable replacement fails. | ||
| > - Handle launch exceptions by logging an error and invoking the callback | ||
| > with an error message. | ||
| ## 1.8.0 | ||
| - 🍏 Support environment variable replacement in Lambda config files | ||
| > If a config file contains placeholders in the form `${ENV_VAR}`, they are | ||
| > replaced with the corresponding environment variable. This feature is not | ||
| > supported by Apex. Use it to configure secret variables in local configs. | ||
| ## 1.7.0 | ||
| - 🙊 Do not log Lambda input and output | ||
| > The new `@studio/wrap` implementation already do logging within the | ||
| > Lambda function. Log filtering should also be applied there. | ||
| ## 1.6.2 | ||
| - 🐛 Pass on parent process `execArgv` | ||
| > This allows to invoke the parent process with v8 options like | ||
| > `--stack-trace-limit=50` and have them passed on to the Lambda | ||
| > processes. This restores the default behavior for child processes. | ||
| ## 1.6.1 | ||
| Log output improvements: | ||
| - 🔢 Include the Lambda execution time in the stats log message | ||
| - 🙈 Set `config_file` to `"<defaults>"` if not found | ||
| - 🙈 Remove messages to streamline log output | ||
| ## 1.6.0 | ||
| - 🔢 Log Lambda process memory usage | ||
| ## 1.5.0 | ||
| - 🍏 Add Lamdba debugging option | ||
| ## 1.4.0 | ||
| - 🍏 Pass on `process.env.DEBUG` | ||
| ## 1.3.3 | ||
| - 🍏 Improve log output filtering | ||
| - 🍏 Handle Lambda logs on stdout | ||
| - 🙈 Do not log `authorizationToken` | ||
| - 🐛 Fix log message with string event | ||
| ## 1.3.2 | ||
| - 🐛 Reduce duplication in log messages | ||
| ## 1.3.1 | ||
| - 🐛 Rename logger | ||
| ## 1.3.0 | ||
| - 🍏 Use `@studio/log` | ||
| ## 1.2.2 | ||
| - 🐛 Handle invalid lambda response | ||
| ## 1.2.1 | ||
| - 🐛 Timeouts are defined in seconds | ||
| ## 1.2.0 | ||
| - 🍏 Add `base_dir` config option | ||
| ## 1.1.2 | ||
| - 🍏 Pass `HOME` environment variable for the `aws-sdk` module to find the | ||
| credentials file | ||
| - ✨ Change log emoji for send and receive events | ||
| ## 1.1.1 | ||
| A few bug fixes and minor improvements: | ||
| - 🐛 Preserve configured env if config file is loaded | ||
| - 🐛 Do not log authorization and token header values | ||
| - 🐛 Prefix log messages with "Lambda" | ||
| - 🐛 Log lambda error response | ||
| ## 1.1.0 | ||
| - 🍏 Allow to pass an optional `context` object to the Lambda handler | ||
| function. If no context is given, it defaults to an empty object, retaining | ||
| the previous behavior. | ||
| ## 1.0.0 | ||
| - ✨ Inception |
Sorry, the diff of this file is not supported yet
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| callback(null, `Other dir ${event.name}`); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| let count = 0; | ||
| exports.handle = function (event, context, callback) { | ||
| count++; | ||
| setTimeout(() => { | ||
| callback(null, `Count ${count}`); | ||
| }, 200); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| const ctx = Object.assign( | ||
| { | ||
| invokedFunctionArn: context.invokedFunctionArn // getter | ||
| }, | ||
| context | ||
| ); | ||
| setTimeout(() => { | ||
| callback(null, JSON.stringify(ctx)); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| callback(null, `Debug ${process.env.DEBUG}`); | ||
| }, 1); | ||
| }; |
| { | ||
| "environment": { | ||
| "STUDIO_ENV_VAR": "Hello", | ||
| "STUDIO_ENV_TPL": "${STUDIO_ENVIRONMENT_VARIABLE}" | ||
| } | ||
| } |
| 'use strict'; | ||
| exports.handle = function () { | ||
| return new Promise((resolve, reject) => { | ||
| setTimeout(() => { | ||
| // eslint-disable-next-line prefer-promise-reject-errors | ||
| reject(`${process.env.STUDIO_ENV_VAR} ${process.env.STUDIO_ENV_TPL}`); | ||
| }, 1); | ||
| }); | ||
| }; |
| { | ||
| "environment": { | ||
| "STUDIO_ENV_VAR": "Hello", | ||
| "STUDIO_ENV_TPL": "${STUDIO_ENVIRONMENT_VARIABLE}" | ||
| } | ||
| } |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| callback( | ||
| null, | ||
| `${process.env.STUDIO_ENV_VAR} ${process.env.STUDIO_ENV_TPL}` | ||
| ); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| callback(null, `Hello ${process.env[event.env]}`); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| callback(null, context.getRemainingTimeInMillis()); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event) { | ||
| return new Promise((resolve) => { | ||
| setTimeout(() => { | ||
| resolve(`Hello ${event.name}`); | ||
| }, 1); | ||
| }); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| callback(null, `Hello ${event.name}`); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| const obj = { | ||
| toJSON() { | ||
| throw new Error('Ouch!'); | ||
| } | ||
| }; | ||
| callback(null, obj); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| console.log('{"some":"incomplete json output'); | ||
| setTimeout(callback, 1); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| callback(null, () => {}); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| const logger = require('@studio/log'); | ||
| const Stringify = require('@studio/ndjson/stringify'); | ||
| logger.pipe(new Stringify()).pipe(process.stdout); | ||
| const log = logger('Test'); | ||
| exports.handle = function (event, context, callback) { | ||
| const err = new Error('Fail'); | ||
| err.cause = new Error('Cause'); | ||
| log.error('Failure', err); | ||
| callback(); | ||
| }; |
| 'use strict'; | ||
| const logger = require('@studio/log'); | ||
| const Stringify = require('@studio/ndjson/stringify'); | ||
| logger.pipe(new Stringify()).pipe(process.stdout); | ||
| const log = logger('Test'); | ||
| exports.handle = function (event, context, callback) { | ||
| log.ok('Check'); | ||
| log.warn({ event }); | ||
| log.error({ event }, new Error()); | ||
| log.wtf(); | ||
| console.log('Raw log line'); | ||
| callback(); | ||
| }; |
| { | ||
| "memory": 8 | ||
| } |
| 'use strict'; | ||
| const count = 1024 * 1024; | ||
| exports.handle = function (event, context, callback) { | ||
| const entries = []; | ||
| try { | ||
| for (let i = 0; i < count; i++) { | ||
| entries.push('a'); | ||
| } | ||
| callback(null, 'Allocated'); | ||
| } catch (e) { | ||
| callback(String(process.memoryUsage().rss)); | ||
| } | ||
| }; |
| 'use strict'; | ||
| let count = 0; | ||
| exports.handle = function (event, context, callback) { | ||
| count++; | ||
| setTimeout(() => { | ||
| callback(null, `Count ${count}`); | ||
| }, 1); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function () { | ||
| throw new Error('Oh noes!'); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (_event, _context, _callback) { | ||
| throw new Error('Oh noes!'); | ||
| }; |
| { | ||
| "timeout": 0.1 | ||
| } |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| // eslint-disable-next-line n/no-callback-literal | ||
| callback('E_TOO_LATE'); | ||
| }, 200); | ||
| }; |
| 'use strict'; | ||
| exports.handle = function (event, context, callback) { | ||
| setTimeout(() => { | ||
| // eslint-disable-next-line n/no-callback-literal | ||
| callback('E_TOO_LATE'); | ||
| }, 200); | ||
| }; |
| 'use strict'; | ||
| process.env.AWS_PROFILE = 'studio-lambda-test'; | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const { assert, match, sinon } = require('@sinonjs/referee-sinon'); | ||
| const logger = require('@studio/log'); | ||
| const Lambda = require('..'); | ||
| const log = logger('Lambda'); | ||
| describe('lambda', () => { | ||
| let lambda; | ||
| before(() => { | ||
| process.chdir(`${__dirname}/fixture`); | ||
| }); | ||
| afterEach(() => { | ||
| sinon.restore(); | ||
| lambda.shutdown(); | ||
| delete process.env.AWS_REGION; | ||
| delete process.env.STUDIO_AWS_ACCOUNT; | ||
| }); | ||
| it('invokes lambda with event', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('hello', { name: 'JavaScript Studio' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello JavaScript Studio'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('invokes async lambda', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke( | ||
| 'hello-async', | ||
| { name: 'JavaScript Studio' }, | ||
| (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello JavaScript Studio'); | ||
| done(); | ||
| } | ||
| ); | ||
| }); | ||
| it('resolves promise if no callback is given', async () => { | ||
| lambda = Lambda.create(); | ||
| const promise = lambda.invoke('hello-async', { | ||
| name: 'JavaScript Studio' | ||
| }); | ||
| await assert.resolves(promise, 'Hello JavaScript Studio'); | ||
| }); | ||
| function hasExpectedErrorMessage(err) { | ||
| return err.message.startsWith( | ||
| 'Lambda invalid-response message parse error' | ||
| ); | ||
| } | ||
| it('handles invalid response', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('invalid-response', {}, (err) => { | ||
| assert.equals(err.name, 'Error'); | ||
| assert.isTrue(hasExpectedErrorMessage(err)); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('rejects promise if no callback is given', async () => { | ||
| lambda = Lambda.create(); | ||
| const promise = lambda.invoke('invalid-response'); | ||
| await assert.rejects(promise, match(hasExpectedErrorMessage)); | ||
| }); | ||
| it('handles invalid JSON', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('invalid-json', {}, (err) => { | ||
| assert.equals(err.name, 'Error'); | ||
| assert.equals(err.message, 'Ouch!'); | ||
| assert.match(err.stack, 'Error: Ouch!\n at '); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('invokes lambda with default context', (done) => { | ||
| sinon.useFakeTimers(123); | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('context', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.json(value, { | ||
| functionName: 'context', | ||
| memoryLimitInMB: 128, | ||
| awsRequestId: '000000123_context_1', | ||
| invokedFunctionArn: | ||
| 'arn:aws:lambda:us-east-1:000000000000:function:context' | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('uses AWS_REGION environment variable in function ARN', (done) => { | ||
| process.env.AWS_REGION = 'eu-central-1'; | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('context', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.matchJson(value, { | ||
| invokedFunctionArn: | ||
| 'arn:aws:lambda:eu-central-1:000000000000:function:context' | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('uses STUDIO_AWS_ACCOUNT environment variable in function ARN', (done) => { | ||
| process.env.STUDIO_AWS_ACCOUNT = '12345678'; | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('context', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.matchJson(value, { | ||
| invokedFunctionArn: 'arn:aws:lambda:us-east-1:12345678:function:context' | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('invokes lambda with given awsRequestId', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('context', {}, { awsRequestId: '666' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.matchJson(value, { | ||
| awsRequestId: '666', | ||
| invokedFunctionArn: | ||
| 'arn:aws:lambda:us-east-1:000000000000:function:context' | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('implements getRemainingTimeInMillis() (default timeout)', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('getRemainingTimeInMillis', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.greater(value, 4950); | ||
| assert.less(value, 5000); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('implements getRemainingTimeInMillis() (configured timeout)', (done) => { | ||
| lambda = Lambda.create({ | ||
| timeout: 1 | ||
| }); | ||
| lambda.invoke('getRemainingTimeInMillis', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.greater(value, 950); | ||
| assert.less(value, 1050); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('invokes lambda with environment variables from options', (done) => { | ||
| lambda = Lambda.create({ | ||
| env: { | ||
| STUDIO_ENV_VAR: 'JavaScript Studio' | ||
| } | ||
| }); | ||
| lambda.invoke('env', { env: 'STUDIO_ENV_VAR' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello JavaScript Studio'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('passes AWS_PROFILE to lambda', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'AWS_PROFILE' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello studio-lambda-test'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('defaults AWS_REGION to us-east-1', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'AWS_REGION' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello us-east-1'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('passes AWS_REGION to lambda', (done) => { | ||
| process.env.AWS_REGION = 'eu-central-1'; | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'AWS_REGION' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello eu-central-1'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('defaults AWS_DEFAULT_REGION to us-east-1', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'AWS_DEFAULT_REGION' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello us-east-1'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('set AWS_DEFAULT_REGION to AWS_REGION', (done) => { | ||
| process.env.AWS_REGION = 'eu-central-1'; | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'AWS_DEFAULT_REGION' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello eu-central-1'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('sets LAMBDA_TASK_ROOT to lambda source dir', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'LAMBDA_TASK_ROOT' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals( | ||
| value, | ||
| `Hello ${path.resolve(__dirname, 'fixture/functions/env')}` | ||
| ); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('sets AWS_EXECUTION_ENV to AWS_Lambda_nodejs6.10', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'AWS_EXECUTION_ENV' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello AWS_Lambda_nodejs6.10'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('sets AWS_LAMBDA_FUNCTION_NAME to lambda name', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'AWS_LAMBDA_FUNCTION_NAME' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello env'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('sets AWS_LAMBDA_FUNCTION_MEMORY_SIZE to lambda name', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke( | ||
| 'env', | ||
| { env: 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE' }, | ||
| (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello 128'); | ||
| done(); | ||
| } | ||
| ); | ||
| }); | ||
| it('sets AWS_LAMBDA_FUNCTION_VERSION to 1', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke( | ||
| 'env', | ||
| { env: 'AWS_LAMBDA_FUNCTION_VERSION' }, | ||
| (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello 1'); | ||
| done(); | ||
| } | ||
| ); | ||
| }); | ||
| it('sets LANG to en_US.UTF-8', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'LANG' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello en_US.UTF-8'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('sets PATH to /usr/local/bin', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'PATH' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello /usr/local/bin'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('sets TZ to UTC', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('env', { env: 'TZ' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello UTC'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('invokes lambda with environment variables from file', (done) => { | ||
| process.env.STUDIO_ENVIRONMENT_VARIABLE = 'JavaScript Studio'; | ||
| lambda = Lambda.create({ | ||
| env: { | ||
| AWS_PROFILE: 'local' | ||
| } | ||
| }); | ||
| lambda.invoke('env-file', {}, (err, value) => { | ||
| delete process.env.STUDIO_ENVIRONMENT_VARIABLE; | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Hello JavaScript Studio'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('fails to launch lambda if environment variable is missing', (done) => { | ||
| lambda = Lambda.create({ | ||
| env: { | ||
| AWS_PROFILE: 'local' | ||
| } | ||
| }); | ||
| lambda.invoke('env-file', {}, (err) => { | ||
| assert.json(err, { | ||
| message: 'Failed to launch "env-file"' | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('fails to launch async lambda if environment variable is missing', async () => { | ||
| lambda = Lambda.create({ | ||
| env: { | ||
| AWS_PROFILE: 'local' | ||
| } | ||
| }); | ||
| const promise = lambda.invoke('env-file-async'); | ||
| await assert.rejects( | ||
| promise, | ||
| match.json({ | ||
| message: 'Failed to launch "env-file-async"' | ||
| }) | ||
| ); | ||
| }); | ||
| it('invokes lambda with DEBUG environment variables', (done) => { | ||
| process.env.DEBUG = 'ON'; | ||
| lambda = Lambda.create({}); | ||
| lambda.invoke('debug', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Debug ON'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('reuses lambda process', (done) => { | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('reuse', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Count 1'); | ||
| // eslint-disable-next-line no-shadow | ||
| lambda.invoke('reuse', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Count 2'); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('runs lambda concurrently', (done) => { | ||
| lambda = Lambda.create(); | ||
| let invokes = 0; | ||
| lambda.invoke('concurrent', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Count 1'); | ||
| if (++invokes === 2) { | ||
| done(); | ||
| } | ||
| }); | ||
| lambda.invoke('concurrent', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Count 1'); | ||
| if (++invokes === 2) { | ||
| done(); | ||
| } | ||
| }); | ||
| }); | ||
| it('shuts down lambda after max_idle', (done) => { | ||
| lambda = Lambda.create({ | ||
| max_idle: 200 | ||
| }); | ||
| lambda.invoke('reuse', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Count 1'); | ||
| setTimeout(() => { | ||
| // eslint-disable-next-line no-shadow | ||
| lambda.invoke('reuse', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Count 1'); | ||
| done(); | ||
| }); | ||
| }, 201); | ||
| }); | ||
| }); | ||
| it('kills lambda after default timeout', (done) => { | ||
| sinon.stub(log, 'warn'); | ||
| lambda = Lambda.create({ | ||
| timeout: 0.1 | ||
| }); | ||
| lambda.invoke('timeout', {}, (err) => { | ||
| assert.json(err, { code: 'E_TIMEOUT' }); | ||
| assert.calledOnce(log.warn); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('kills lambda after configured timeout', (done) => { | ||
| sinon.stub(log, 'warn'); | ||
| lambda = Lambda.create({ | ||
| env: { | ||
| AWS_PROFILE: 'local' | ||
| } | ||
| }); | ||
| lambda.invoke('timeout-file', {}, (err) => { | ||
| assert.json(err, { code: 'E_TIMEOUT' }); | ||
| assert.calledOnce(log.warn); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('kills lambda after configured timeout if larger than max_idle', (done) => { | ||
| sinon.stub(log, 'warn'); | ||
| lambda = Lambda.create({ | ||
| max_idle: 25, | ||
| env: { | ||
| AWS_PROFILE: 'local' | ||
| } | ||
| }); | ||
| lambda.invoke('timeout-file', {}, (err) => { | ||
| assert.json(err, { code: 'E_TIMEOUT' }); | ||
| assert.calledOnce(log.warn); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('does not fail to talk to lambda after two where killed', (done) => { | ||
| sinon.stub(log, 'warn'); | ||
| lambda = Lambda.create({ | ||
| timeout: 0.1 | ||
| }); | ||
| lambda.invoke('timeout', {}, (err) => { | ||
| assert.json(err, { code: 'E_TIMEOUT' }); | ||
| }); | ||
| lambda.invoke('timeout', {}, (err) => { | ||
| assert.json(err, { code: 'E_TIMEOUT' }); | ||
| // eslint-disable-next-line no-shadow | ||
| lambda.invoke('timeout', {}, (err) => { | ||
| assert.json(err, { code: 'E_TIMEOUT' }); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('uses given base_dir', (done) => { | ||
| lambda = Lambda.create({ | ||
| base_dir: `${__dirname}/fixture/cwd` | ||
| }); | ||
| lambda.invoke('hello', { name: 'works' }, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Other dir works'); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('handles log output', (done) => { | ||
| const lambda_log = logger('Lambda log'); | ||
| const lambda_test_log = logger('Lambda log Test'); | ||
| lambda = Lambda.create(); | ||
| sinon.stub(lambda_log, 'ignore'); | ||
| sinon.stub(lambda_test_log, 'ok'); | ||
| sinon.stub(lambda_test_log, 'warn'); | ||
| sinon.stub(lambda_test_log, 'error'); | ||
| sinon.stub(lambda_test_log, 'wtf'); | ||
| lambda.invoke('log', { is: 42 }, (err) => { | ||
| assert.isNull(err); | ||
| assert.calledOnceWith(lambda_log.ignore, 'Raw log line'); | ||
| assert.calledOnceWith(lambda_test_log.ok, 'Check'); | ||
| assert.calledOnceWith(lambda_test_log.warn, { event: { is: 42 } }); | ||
| assert.calledOnceWith( | ||
| lambda_test_log.error, | ||
| { event: { is: 42 } }, | ||
| match({ stack: match.string }) | ||
| ); | ||
| assert.calledOnce(lambda_test_log.wtf); | ||
| assert.calledWithExactly(lambda_test_log.wtf); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('handles error log output with cause', (done) => { | ||
| const lambda_test_log = logger('Lambda log-error-cause Test'); | ||
| lambda = Lambda.create(); | ||
| sinon.stub(lambda_test_log, 'error'); | ||
| lambda.invoke('log-error-cause', {}, (err) => { | ||
| assert.isNull(err); | ||
| assert.calledOnceWith( | ||
| lambda_test_log.error, | ||
| 'Failure', | ||
| match({ | ||
| stack: match('Fail'), | ||
| cause: match('Cause') | ||
| }) | ||
| ); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('handles invalid log output', (done) => { | ||
| const lambda_log = logger('Lambda invalid-log'); | ||
| sinon.stub(lambda_log, 'ignore'); | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('invalid-log', {}, (err) => { | ||
| assert.isNull(err); | ||
| assert.calledOnceWith( | ||
| lambda_log.ignore, | ||
| '{"some":"incomplete json output' | ||
| ); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('handles throwing lambda', (done) => { | ||
| sinon.stub(process.stderr, 'write'); | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('throw', {}, (err) => { | ||
| assert.json(err, { code: 'E_FAILED' }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('handles throwing async lambda', (done) => { | ||
| sinon.stub(process.stderr, 'write'); | ||
| lambda = Lambda.create(); | ||
| lambda.invoke('throw-async', {}, (err) => { | ||
| assert.json(err, { code: 'E_FAILED' }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('runs node process with default memory', (done) => { | ||
| lambda = Lambda.create({}); | ||
| lambda.invoke('memory', {}, (err, value) => { | ||
| assert.isNull(err); | ||
| assert.equals(value, 'Allocated'); | ||
| done(); | ||
| }); | ||
| }); | ||
| context('with memory limit', () => { | ||
| after(() => { | ||
| // Remove the node memory report. | ||
| const dir = `${__dirname}/fixture/functions/memory`; | ||
| // eslint-disable-next-line n/no-sync | ||
| fs.readdirSync(dir) | ||
| .filter((file) => file.startsWith('report.')) | ||
| .forEach((file) => { | ||
| // eslint-disable-next-line n/no-sync | ||
| fs.unlinkSync(`${dir}/${file}`); | ||
| }); | ||
| }); | ||
| it('runs node process with memory from config file', (done) => { | ||
| sinon.stub(process.stderr, 'write'); | ||
| lambda = Lambda.create({ | ||
| env: { | ||
| AWS_PROFILE: 'local' | ||
| } | ||
| }); | ||
| lambda.invoke('memory', {}, (err) => { | ||
| assert.json(err, { code: 'E_FAILED' }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('runs node process with memory from property', (done) => { | ||
| sinon.stub(process.stderr, 'write'); | ||
| lambda = Lambda.create({ | ||
| memory: 8 | ||
| }); | ||
| lambda.invoke('memory', {}, (err) => { | ||
| assert.json(err, { code: 'E_FAILED' }); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| }); |
| 'use strict'; | ||
| process.env.AWS_PROFILE = 'studio-lambda-test'; | ||
| const { assert } = require('@sinonjs/referee-sinon'); | ||
| const Lambda = require('..'); | ||
| describe('shutdown', () => { | ||
| before(() => { | ||
| process.chdir(`${__dirname}/fixture`); | ||
| }); | ||
| it('removes any running instance', (done) => { | ||
| const lambda = Lambda.create(); | ||
| lambda.invoke('hello', { name: 'X' }, () => { | ||
| lambda.shutdown(); | ||
| const stats = lambda.stats(); | ||
| assert.isObject(stats.hello); | ||
| assert.equals(stats.hello.instances, 0); | ||
| assert.equals(stats.hello.requests, 1); | ||
| assert.equals(stats.hello.active, 0); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('fails pending instance', (done) => { | ||
| const lambda = Lambda.create(); | ||
| lambda.invoke('hello', { name: 'X' }, (err) => { | ||
| assert.json(err, { code: 'E_FAILED' }); | ||
| const stats = lambda.stats(); | ||
| assert.isObject(stats.hello); | ||
| assert.equals(stats.hello.instances, 0); | ||
| assert.equals(stats.hello.requests, 1); | ||
| assert.equals(stats.hello.active, 0); | ||
| done(); | ||
| }); | ||
| lambda.shutdown(); | ||
| }); | ||
| it('waits for pending instance if graceful options is true', (done) => { | ||
| const lambda = Lambda.create(); | ||
| lambda.invoke('hello', { name: 'X' }, (err) => { | ||
| assert.isNull(err); | ||
| const stats = lambda.stats(); | ||
| assert.isObject(stats.hello); | ||
| assert.equals(stats.hello.instances, 0); | ||
| assert.equals(stats.hello.requests, 1); | ||
| assert.equals(stats.hello.active, 0); | ||
| done(); | ||
| }); | ||
| lambda.shutdown({ graceful: true }); | ||
| }); | ||
| it('waits for timeout instance if graceful options is true', (done) => { | ||
| const lambda = Lambda.create({ | ||
| timeout: 0.1 | ||
| }); | ||
| lambda.invoke('timeout', { name: 'X' }, (err) => { | ||
| assert.json(err, { code: 'E_TIMEOUT' }); | ||
| const stats = lambda.stats(); | ||
| assert.isObject(stats.timeout); | ||
| assert.equals(stats.timeout.instances, 0); | ||
| assert.equals(stats.timeout.requests, 1); | ||
| assert.equals(stats.timeout.active, 0); | ||
| done(); | ||
| }); | ||
| lambda.shutdown({ graceful: true }); | ||
| }); | ||
| }); |
| 'use strict'; | ||
| process.env.AWS_PROFILE = 'studio-lambda-test'; | ||
| const { assert } = require('@sinonjs/referee-sinon'); | ||
| const Lambda = require('..'); | ||
| describe('stats', () => { | ||
| let lambda; | ||
| before(() => { | ||
| process.chdir(`${__dirname}/fixture`); | ||
| }); | ||
| beforeEach(() => { | ||
| lambda = Lambda.create(); | ||
| }); | ||
| afterEach(() => { | ||
| lambda.shutdown(); | ||
| }); | ||
| it('counts first instance and request', (done) => { | ||
| lambda.invoke('hello', { name: 'Stats' }, () => { | ||
| const stats = lambda.stats(); | ||
| assert.isObject(stats.hello); | ||
| assert.equals(stats.hello.instances, 1); | ||
| assert.equals(stats.hello.requests, 1); | ||
| assert.equals(stats.hello.active, 0); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('counts sequential requests', (done) => { | ||
| lambda.invoke('hello', { name: 'A' }, () => { | ||
| lambda.invoke('hello', { name: 'B' }, () => { | ||
| const stats = lambda.stats(); | ||
| assert.isObject(stats.hello); | ||
| assert.equals(stats.hello.instances, 1); | ||
| assert.equals(stats.hello.requests, 2); | ||
| assert.equals(stats.hello.active, 0); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| it('counts concurrent requests', (done) => { | ||
| let count = 2; | ||
| const latch = () => { | ||
| if (--count === 0) { | ||
| const stats = lambda.stats(); | ||
| assert.isObject(stats.hello); | ||
| assert.equals(stats.hello.instances, 2); | ||
| assert.equals(stats.hello.requests, 2); | ||
| assert.equals(stats.hello.active, 0); | ||
| done(); | ||
| } | ||
| }; | ||
| lambda.invoke('hello', { name: 'A' }, latch); | ||
| lambda.invoke('hello', { name: 'B' }, latch); | ||
| }); | ||
| it('counts active instances', (done) => { | ||
| lambda.invoke('hello', {}, () => {}); | ||
| lambda.invoke('hello', {}, () => {}); | ||
| const stats = lambda.stats(); | ||
| assert.isObject(stats.hello); | ||
| assert.equals(stats.hello.instances, 2); | ||
| assert.equals(stats.hello.requests, 2); | ||
| assert.equals(stats.hello.active, 2); | ||
| done(); | ||
| }); | ||
| }); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 7 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 10 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
14
-57.58%18159
-68.95%5
-87.5%447
-65.85%2
100%Updated