Skip to content

Commit

Permalink
fix: Support handlers exported from nested modules (#1348)
Browse files Browse the repository at this point in the history
  • Loading branch information
akinboboye committed Mar 18, 2022
1 parent c90b8bf commit e7c72f4
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 164 deletions.
4 changes: 3 additions & 1 deletion src/lambda/LambdaFunction.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ export default class LambdaFunction {
const _servicePath = resolve(servicePath, options.location || '')

const { handler, name, package: functionPackage = {} } = functionDefinition
const [handlerPath, handlerName] = splitHandlerPathAndName(handler)
const [handlerPath, handlerName, handlerModuleNesting] =
splitHandlerPathAndName(handler)

const memorySize =
functionDefinition.memorySize ||
Expand Down Expand Up @@ -113,6 +114,7 @@ export default class LambdaFunction {
functionKey,
handler,
handlerName,
handlerModuleNesting,
codeDir: this.#codeDir,
handlerPath: resolve(this.#codeDir, handlerPath),
runtime,
Expand Down
145 changes: 0 additions & 145 deletions src/lambda/__tests__/fixtures/lambdaFunction.fixture.js

This file was deleted.

123 changes: 123 additions & 0 deletions src/lambda/__tests__/fixtures/lambdaFunction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
'use strict'

exports.fixture = {
contextDoneHandler(event, context) {
context.done(null, 'foo')
},

contextDoneHandlerDeferred(event, context) {
setTimeout(() => context.done(null, 'foo'), 100)
},

contextSucceedHandler(event, context) {
context.succeed('foo')
},

contextSucceedHandlerDeferred(event, context) {
setTimeout(() => context.succeed('foo'), 100)
},

callbackHandler(event, context, callback) {
callback(null, 'foo')
},

callbackHandlerDeferred(event, context, callback) {
setTimeout(() => callback(null, 'foo'), 100)
},

promiseHandler() {
return Promise.resolve('foo')
},

promiseHandlerDeferred() {
return new Promise((resolve) => {
setTimeout(() => resolve('foo'), 100)
})
},

async asyncFunctionHandler() {
return 'foo'
},

async asyncFunctionHandlerObject() {
return {
foo: 'bar',
}
},

// we deliberately test the case where a 'callback' is defined
// in the handler, but a promise is being returned to protect from a
// potential naive implementation, e.g.
//
// const { promisify } = 'utils'
// const promisifiedHandler = handler.length === 3 ? promisify(handler) : handler
//
// if someone would return a promise, but also defines callback, without using it
// the handler would not be returning anything

promiseWithDefinedCallbackHandler(
event, // eslint-disable-line no-unused-vars
context, // eslint-disable-line no-unused-vars
callback, // eslint-disable-line no-unused-vars
) {
return Promise.resolve('Hello Promise!')
},

contextSucceedWithContextDoneHandler(event, context) {
context.succeed('Hello Context.succeed!')

context.done(null, 'Hello Context.done!')
},

callbackWithContextDoneHandler(event, context, callback) {
callback(null, 'Hello Callback!')

context.done(null, 'Hello Context.done!')
},

callbackWithPromiseHandler(event, context, callback) {
callback(null, 'Hello Callback!')

return Promise.resolve('Hello Promise!')
},

callbackInsidePromiseHandler(event, context, callback) {
return new Promise((resolve) => {
callback(null, 'Hello Callback!')

resolve('Hello Promise!')
})
},

async requestIdHandler(event, context) {
return context.awsRequestId
},

async remainingExecutionTimeHandler(event, context) {
const first = context.getRemainingTimeInMillis()

await new Promise((resolve) => {
setTimeout(resolve, 100)
})

const second = context.getRemainingTimeInMillis()

await new Promise((resolve) => {
setTimeout(resolve, 200)
})

const third = context.getRemainingTimeInMillis()

return [first, second, third]
},

async defaultTimeoutHandler(event, context) {
return context.getRemainingTimeInMillis()
},

executionTimeInMillisHandler() {
return new Promise((resolve) => {
setTimeout(resolve, 100)
})
},
}
11 changes: 9 additions & 2 deletions src/lambda/handler-runner/HandlerRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@ export default class HandlerRunner {
const { useDocker, useChildProcesses, useWorkerThreads, allowCache } =
this.#options

const { functionKey, handlerName, handlerPath, runtime, timeout } =
this.#funOptions
const {
functionKey,
handlerName,
handlerPath,
handlerModuleNesting,
runtime,
timeout,
} = this.#funOptions

if (this.log) {
this.log.debug(`Loading handler... (${handlerPath})`)
Expand Down Expand Up @@ -111,6 +117,7 @@ export default class HandlerRunner {
functionKey,
handlerPath,
handlerName,
handlerModuleNesting,
this.#env,
timeout,
allowCache,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@ export default class ChildProcessRunner {
#functionKey = null
#handlerName = null
#handlerPath = null
#handlerModuleNesting = null
#timeout = null
#allowCache = false

constructor(funOptions, env, allowCache, v3Utils) {
const { functionKey, handlerName, handlerPath, timeout } = funOptions
const {
functionKey,
handlerName,
handlerPath,
handlerModuleNesting,
timeout,
} = funOptions

if (v3Utils) {
this.log = v3Utils.log
Expand All @@ -25,6 +32,7 @@ export default class ChildProcessRunner {
this.#functionKey = functionKey
this.#handlerName = handlerName
this.#handlerPath = handlerPath
this.#handlerModuleNesting = handlerModuleNesting
this.#timeout = timeout
this.#allowCache = allowCache
}
Expand All @@ -36,7 +44,12 @@ export default class ChildProcessRunner {
async run(event, context) {
const childProcess = node(
childProcessHelperPath,
[this.#functionKey, this.#handlerName, this.#handlerPath],
[
this.#functionKey,
this.#handlerName,
this.#handlerPath,
this.#handlerModuleNesting,
],
{
env: this.#env,
stdio: 'inherit',
Expand Down

0 comments on commit e7c72f4

Please sign in to comment.