From 0dacf7ad3db93e303befa03a6fe71d20216d0e6d Mon Sep 17 00:00:00 2001 From: Daniel Nalborczyk Date: Wed, 17 Aug 2022 16:46:41 -0400 Subject: [PATCH] fix!: remove child process option --- README.md | 10 --- src/config/commandOptions.js | 5 -- src/config/defaultOptions.js | 1 - src/events/http/HttpServer.js | 15 +--- src/lambda/handler-runner/HandlerRunner.js | 10 +-- .../ChildProcessRunner.js | 75 ------------------- .../childProcessHelper.js | 45 ----------- .../child-process-runner/index.js | 1 - .../instances/child-process-instances.test.js | 37 --------- .../child-processes/instances/serverless.yml | 26 ------- .../child-processes/instances/src/handler.js | 20 ----- .../instances/src/package.json | 3 - 12 files changed, 2 insertions(+), 246 deletions(-) delete mode 100644 src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js delete mode 100644 src/lambda/handler-runner/child-process-runner/childProcessHelper.js delete mode 100644 src/lambda/handler-runner/child-process-runner/index.js delete mode 100644 tests/lambda-run-mode/child-processes/instances/child-process-instances.test.js delete mode 100644 tests/lambda-run-mode/child-processes/instances/serverless.yml delete mode 100644 tests/lambda-run-mode/child-processes/instances/src/handler.js delete mode 100644 tests/lambda-run-mode/child-processes/instances/src/package.json diff --git a/README.md b/README.md index 9d4e51ec4..889cbbfa9 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,6 @@ All CLI options are optional: --printOutput Turns on logging of your lambda outputs in the terminal. --reloadHandler Reloads handler with each request. --resourceRoutes Turns on loading of your HTTP proxy settings from serverless.yml ---useChildProcesses [This option is deprecated] Run handlers in a child process. --useDocker Run handlers in a docker container. --useInProcess Run handlers in the same process as 'serverless-offline'. --webSocketHardTimeout Set WebSocket hard timeout in seconds to reproduce AWS limits (https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html#apigateway-execution-service-websocket-limits-table). Default: 7200 (2 hours) @@ -188,15 +187,6 @@ Lambda handlers for the `node.js` runtime can run in different execution modes w - global state is being shared across lambda handlers as well as with `serverless` and `serverless-offline` - easy debugging -#### child-processes - -- handlers run in a separate node.js instance -- memory is not being shared between handlers, memory consumption is therefore higher -- memory is being released when handlers reload or after usage -- environment (process.env) is not being shared across handlers -- global state is not being shared across handlers -- debugging more complicated - #### docker - handlers run in a docker container diff --git a/src/config/commandOptions.js b/src/config/commandOptions.js index 87ea22e1b..6c5a5d65a 100644 --- a/src/config/commandOptions.js +++ b/src/config/commandOptions.js @@ -130,11 +130,6 @@ export default { type: 'boolean', usage: 'Turns on loading of your HTTP proxy settings from serverless.yml.', }, - useChildProcesses: { - type: 'boolean', - usage: - '[This option is deprecated] Use separate node process to run handlers.', - }, useDocker: { type: 'boolean', usage: 'Uses docker for node/python/ruby/provided', diff --git a/src/config/defaultOptions.js b/src/config/defaultOptions.js index 2eff2cfd8..ef8052c94 100644 --- a/src/config/defaultOptions.js +++ b/src/config/defaultOptions.js @@ -29,7 +29,6 @@ export default { printOutput: false, reloadHandler: false, resourceRoutes: false, - useChildProcesses: false, useDocker: false, useInProcess: false, webSocketHardTimeout: 7200, diff --git a/src/events/http/HttpServer.js b/src/events/http/HttpServer.js index 68af67886..508acdac8 100644 --- a/src/events/http/HttpServer.js +++ b/src/events/http/HttpServer.js @@ -580,21 +580,8 @@ export default class HttpServer { // Failure handling let errorStatusCode = '502' - if (err) { - // Since the --useChildProcesses option loads the handler in - // a separate process and serverless-offline communicates with it - // over IPC, we are unable to catch JavaScript unhandledException errors - // when the handler code contains bad JavaScript. Instead, we "catch" - // it here and reply in the same way that we would have above when - // we lazy-load the non-IPC handler function. - if (this.#options.useChildProcesses && err.ipcException) { - return this.#reply502( - response, - `Error while loading ${functionKey}`, - err, - ) - } + if (err) { const errorMessage = (err.message || err).toString() const found = errorMessage.match(/\[(\d{3})]/) diff --git a/src/lambda/handler-runner/HandlerRunner.js b/src/lambda/handler-runner/HandlerRunner.js index ae0af3372..e075f3945 100644 --- a/src/lambda/handler-runner/HandlerRunner.js +++ b/src/lambda/handler-runner/HandlerRunner.js @@ -23,7 +23,7 @@ export default class HandlerRunner { } async #loadRunner() { - const { useChildProcesses, useDocker, useInProcess } = this.#options + const { useDocker, useInProcess } = this.#options const { handler, runtime } = this.#funOptions log.debug(`Loading handler... (${handler})`) @@ -56,14 +56,6 @@ export default class HandlerRunner { } if (supportedNodejs.has(runtime)) { - if (useChildProcesses) { - const { default: ChildProcessRunner } = await import( - './child-process-runner/index.js' - ) - - return new ChildProcessRunner(this.#funOptions, this.#env) - } - if (useInProcess) { const { default: InProcessRunner } = await import( './in-process-runner/index.js' diff --git a/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js b/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js deleted file mode 100644 index db427e045..000000000 --- a/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +++ /dev/null @@ -1,75 +0,0 @@ -import { dirname, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' -import { log } from '@serverless/utils/log.js' -import { execaNode } from 'execa' - -const __dirname = dirname(fileURLToPath(import.meta.url)) -const childProcessHelperPath = resolve(__dirname, 'childProcessHelper.js') - -export default class ChildProcessRunner { - #codeDir = null - - #env = null - - #functionKey = null - - #handler = null - - #servicePath = null - - #timeout = null - - constructor(funOptions, env) { - const { codeDir, functionKey, handler, servicePath, timeout } = funOptions - - this.#codeDir = codeDir - this.#env = env - this.#functionKey = functionKey - this.#handler = handler - this.#servicePath = servicePath - this.#timeout = timeout - } - - // no-op - // () => void - cleanup() {} - - async run(event, context) { - const childProcess = execaNode( - childProcessHelperPath, - [this.#functionKey, this.#handler, this.#servicePath, this.#codeDir], - { - env: this.#env, - stdio: 'inherit', - }, - ) - - childProcess.send({ - context, - event, - timeout: this.#timeout, - }) - - let result - - try { - result = await new Promise((res, rej) => { - childProcess.on('message', (data) => { - if (data.error) { - rej(data.error) - return - } - res(data.result) - }) - }) - } catch (err) { - // TODO - log.error(err) - throw err - } finally { - childProcess.kill() - } - - return result - } -} diff --git a/src/lambda/handler-runner/child-process-runner/childProcessHelper.js b/src/lambda/handler-runner/child-process-runner/childProcessHelper.js deleted file mode 100644 index 5dd3e77da..000000000 --- a/src/lambda/handler-runner/child-process-runner/childProcessHelper.js +++ /dev/null @@ -1,45 +0,0 @@ -import process, { argv } from 'node:process' -import InProcessRunner from '../in-process-runner/index.js' - -// TODO handle this: -process.on('uncaughtException', (err) => { - const { - constructor: { name }, - message, - stack, - } = err - - process.send({ - // process.send() can't serialize an Error object, so we help it out a bit - error: { - constructor: { - name, - }, - message, - stack, - }, - }) -}) - -const [, , functionKey, handler, servicePath, codeDir] = argv - -process.on('message', async (messageData) => { - const { context, event, timeout } = messageData - - // TODO we could probably cache this in the module scope? - const inProcessRunner = new InProcessRunner( - { - codeDir, - functionKey, - handler, - servicePath, - timeout, - }, - process.env, - ) - - const result = await inProcessRunner.run(event, context) - - // TODO check serializeability (contains function, symbol etc) - process.send({ result }) -}) diff --git a/src/lambda/handler-runner/child-process-runner/index.js b/src/lambda/handler-runner/child-process-runner/index.js deleted file mode 100644 index 759fe7450..000000000 --- a/src/lambda/handler-runner/child-process-runner/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ChildProcessRunner.js' diff --git a/tests/lambda-run-mode/child-processes/instances/child-process-instances.test.js b/tests/lambda-run-mode/child-processes/instances/child-process-instances.test.js deleted file mode 100644 index bb42c7a86..000000000 --- a/tests/lambda-run-mode/child-processes/instances/child-process-instances.test.js +++ /dev/null @@ -1,37 +0,0 @@ -import assert from 'node:assert' -import { dirname, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' -import { setup, teardown } from '../../../_testHelpers/index.js' -import { BASE_URL } from '../../../config.js' - -const __dirname = dirname(fileURLToPath(import.meta.url)) - -describe('run mode with child processes', function desc() { - beforeEach(() => - setup({ - servicePath: resolve(__dirname), - }), - ) - - afterEach(() => teardown()) - - it('should create a new lambda instance', async () => { - const url = new URL('/dev/foo', BASE_URL) - - const responses = await Promise.all( - Array.from(Array(10).keys()).map(() => fetch(url)), - ) - - responses.forEach((response) => { - assert.equal(response.status, 200) - }) - - const jsons = await Promise.all( - responses.map((response) => response.json()), - ) - - jsons.forEach((json) => { - assert.deepEqual(json, 1) - }) - }) -}) diff --git a/tests/lambda-run-mode/child-processes/instances/serverless.yml b/tests/lambda-run-mode/child-processes/instances/serverless.yml deleted file mode 100644 index 86425997a..000000000 --- a/tests/lambda-run-mode/child-processes/instances/serverless.yml +++ /dev/null @@ -1,26 +0,0 @@ -service: run-mode-tests - -configValidationMode: error - -plugins: - - ../../../../ - -custom: - serverless-offline: - useChildProcesses: true - -provider: - memorySize: 128 - name: aws - region: us-east-1 # default - runtime: nodejs16.x - stage: dev - versionFunctions: false - -functions: - foo: - events: - - http: - method: get - path: foo - handler: src/handler.foo diff --git a/tests/lambda-run-mode/child-processes/instances/src/handler.js b/tests/lambda-run-mode/child-processes/instances/src/handler.js deleted file mode 100644 index 40a5baf88..000000000 --- a/tests/lambda-run-mode/child-processes/instances/src/handler.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict' - -const { promisify } = require('node:util') - -const setTimeoutPromise = promisify(setTimeout) - -const { stringify } = JSON - -let counter = 0 - -exports.foo = async function foo() { - counter += 1 - - await setTimeoutPromise(1000, 'result') - - return { - body: stringify(counter), - statusCode: 200, - } -} diff --git a/tests/lambda-run-mode/child-processes/instances/src/package.json b/tests/lambda-run-mode/child-processes/instances/src/package.json deleted file mode 100644 index 5bbefffba..000000000 --- a/tests/lambda-run-mode/child-processes/instances/src/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "commonjs" -}