Skip to content

Commit b60c1ab

Browse files
committed
Allow passing HandlerFunction to run directly
1 parent f9373b3 commit b60c1ab

File tree

7 files changed

+209
-3
lines changed

7 files changed

+209
-3
lines changed

src/Common/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,7 @@ export type HandlerFunction = (
7878
data: IEnvironmentData & IHeaderData,
7979
callback: CallbackFunction
8080
) => PromiseLike<unknown> | unknown;
81+
82+
export function isHandlerFunction(value: any): value is HandlerFunction {
83+
return typeof value === "function";
84+
}

src/index.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
"use strict";
1010

11-
import { HandlerFunction } from "./Common";
11+
import { HandlerFunction, isHandlerFunction } from "./Common";
1212
import * as Errors from "./Errors";
1313
import RuntimeClient from "./RuntimeClient";
1414
import Runtime from "./Runtime";
@@ -18,7 +18,13 @@ import * as UserFunction from "./utils/UserFunction";
1818

1919
LogPatch.patchConsole();
2020

21-
export function run(appRoot: string, handler: string): void {
21+
export function run(appRoot: string, handler: string): void;
22+
export function run(handler: HandlerFunction): void;
23+
24+
export function run(
25+
appRootOrHandler: string | HandlerFunction,
26+
handler: string = ""
27+
): void {
2228
if (!process.env.AWS_LAMBDA_RUNTIME_API) {
2329
throw new Error("Missing Runtime API Server configuration.");
2430
}
@@ -50,7 +56,9 @@ export function run(appRoot: string, handler: string): void {
5056
BeforeExitListener.reset();
5157
process.on("beforeExit", BeforeExitListener.invoke);
5258

53-
const handlerFunc = UserFunction.load(appRoot, handler) as HandlerFunction;
59+
const handlerFunc = isHandlerFunction(appRootOrHandler)
60+
? appRootOrHandler
61+
: (UserFunction.load(appRootOrHandler, handler) as HandlerFunction);
5462
const runtime = new Runtime(client, handlerFunc, errorCallbacks);
5563

5664
runtime.scheduleIteration();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
version: 0.2
2+
3+
env:
4+
variables:
5+
OS_DISTRIBUTION: alpine
6+
NODE_BINARY_LOCATION: "/usr/local/bin/node"
7+
NPX_BINARY_LOCATION: "/usr/local/bin/npx"
8+
batch:
9+
build-matrix:
10+
static:
11+
ignore-failure: false
12+
env:
13+
type: LINUX_CONTAINER
14+
privileged-mode: true
15+
dynamic:
16+
env:
17+
variables:
18+
DISTRO_VERSION:
19+
- "3.12"
20+
RUNTIME_VERSION:
21+
- "12"
22+
- "14"
23+
phases:
24+
pre_build:
25+
commands:
26+
- export IMAGE_TAG="nodejs-${OS_DISTRIBUTION}-${DISTRO_VERSION}:${RUNTIME_VERSION}"
27+
- echo "Extracting and including the Runtime Interface Emulator"
28+
- SCRATCH_DIR=".scratch"
29+
- mkdir "${SCRATCH_DIR}"
30+
- tar -xvf test/integration/resources/aws-lambda-rie.tar.gz --directory "${SCRATCH_DIR}"
31+
- >
32+
cp "test/integration/docker/Dockerfile.programmatic.${OS_DISTRIBUTION}" \
33+
"${SCRATCH_DIR}/Dockerfile.programmatic.${OS_DISTRIBUTION}.tmp"
34+
- >
35+
echo "RUN apk add curl" >> \
36+
"${SCRATCH_DIR}/Dockerfile.programmatic.${OS_DISTRIBUTION}.tmp"
37+
- >
38+
echo "COPY ${SCRATCH_DIR}/aws-lambda-rie /usr/bin/aws-lambda-rie" >> \
39+
"${SCRATCH_DIR}/Dockerfile.programmatic.${OS_DISTRIBUTION}.tmp"
40+
- >
41+
if [[ -z "${DOCKERHUB_USERNAME}" && -z "${DOCKERHUB_PASSWORD}" ]];
42+
then
43+
echo "DockerHub credentials not set as CodeBuild environment variables. Continuing without docker login."
44+
else
45+
echo "Performing DockerHub login . . ."
46+
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD
47+
fi
48+
- echo "Building image ${IMAGE_TAG}"
49+
- >
50+
docker build . \
51+
-f "${SCRATCH_DIR}/Dockerfile.programmatic.${OS_DISTRIBUTION}.tmp" \
52+
-t "${IMAGE_TAG}" \
53+
--build-arg RUNTIME_VERSION="${RUNTIME_VERSION}" \
54+
--build-arg DISTRO_VERSION="${DISTRO_VERSION}"
55+
build:
56+
commands:
57+
- set -x
58+
- echo "Running Image ${IMAGE_TAG}"
59+
- docker network create "${OS_DISTRIBUTION}-network"
60+
- >
61+
docker run \
62+
--detach \
63+
-e "NODE_BINARY_LOCATION=${NODE_BINARY_LOCATION}" \
64+
--name "${OS_DISTRIBUTION}-app" \
65+
--network "${OS_DISTRIBUTION}-network" \
66+
--entrypoint="" \
67+
"${IMAGE_TAG}" \
68+
sh -c '/usr/bin/aws-lambda-rie ${NODE_BINARY_LOCATION} index.js'
69+
- sleep 2
70+
- >
71+
docker run \
72+
--name "${OS_DISTRIBUTION}-tester" \
73+
--env "TARGET=${OS_DISTRIBUTION}-app" \
74+
--network "${OS_DISTRIBUTION}-network" \
75+
--entrypoint="" \
76+
"${IMAGE_TAG}" \
77+
sh -c 'curl -X POST "http://${TARGET}:8080/2015-03-31/functions/function/invocations" -d "{}" --max-time 10'
78+
- actual="$(docker logs --tail 1 "${OS_DISTRIBUTION}-tester" | xargs)"
79+
- expected='success'
80+
- |
81+
echo "Response: ${actual}"
82+
if [[ "$actual" != "$expected" ]]; then
83+
echo "fail! runtime: $RUNTIME - expected output $expected - got $actual"
84+
echo "---------Container Logs: ${OS_DISTRIBUTION}-app----------"
85+
echo
86+
docker logs "${OS_DISTRIBUTION}-app"
87+
echo
88+
echo "---------------------------------------------------"
89+
echo "--------Container Logs: ${OS_DISTRIBUTION}-tester--------"
90+
echo
91+
docker logs "${OS_DISTRIBUTION}-tester"
92+
echo
93+
echo "---------------------------------------------------"
94+
exit -1
95+
fi
96+
finally:
97+
- echo "Cleaning up..."
98+
- docker stop "${OS_DISTRIBUTION}-app" || true
99+
- docker rm --force "${OS_DISTRIBUTION}-app" || true
100+
- docker stop "${OS_DISTRIBUTION}-tester" || true
101+
- docker rm --force "${OS_DISTRIBUTION}-tester" || true
102+
- docker network rm "${OS_DISTRIBUTION}-network" || true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Define global args
2+
ARG FUNCTION_DIR="/home/app/"
3+
ARG RUNTIME_VERSION
4+
ARG DISTRO_VERSION
5+
6+
# Stage 1 - build function and dependencies
7+
FROM node:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS build-image
8+
# Install aws-lambda-cpp build dependencies
9+
RUN apk add --update-cache \
10+
build-base \
11+
libtool \
12+
musl-dev \
13+
libressl-dev \
14+
libffi-dev \
15+
autoconf \
16+
automake \
17+
libexecinfo-dev \
18+
make \
19+
cmake \
20+
python3 \
21+
libcurl
22+
23+
# Include global arg in this stage of the build
24+
ARG FUNCTION_DIR
25+
# Create function directory
26+
RUN mkdir -p ${FUNCTION_DIR}
27+
28+
# Copy & build Runtime Interface Client package (as we're installing it from a local filesystem source)
29+
WORKDIR ${FUNCTION_DIR}/deps/aws-lambda-ric
30+
COPY . .
31+
RUN make build && \
32+
npm run test:unit
33+
34+
# Copy function code
35+
COPY test/integration/test-handlers/programmatic/* ${FUNCTION_DIR}
36+
# Install the function's dependencies
37+
WORKDIR ${FUNCTION_DIR}
38+
RUN npm install
39+
40+
41+
# Stage 2 - final runtime image
42+
# Grab a fresh copy of the Node image
43+
FROM node:${RUNTIME_VERSION}-alpine${DISTRO_VERSION}
44+
45+
# Include global arg in this stage of the build
46+
ARG FUNCTION_DIR
47+
# Set working directory to function root directory
48+
WORKDIR ${FUNCTION_DIR}
49+
# Copy in the built dependencies
50+
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
51+
52+
CMD [ "/usr/local/bin/node", "index.js" ]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const ric = require('aws-lambda-ric');
2+
3+
const echo = async (event, context) => {
4+
console.log('hello world');
5+
return 'success';
6+
};
7+
8+
ric.run(echo);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "programmatic-hanlder",
3+
"version": "1.0.0",
4+
"description": "Sample Lambda echo handler for NodeJS",
5+
"main": "app.js",
6+
"author": "AWS Lambda",
7+
"license": "Apache-2.0",
8+
"dependencies": {
9+
"aws-lambda-ric": "file:deps/aws-lambda-ric"
10+
}
11+
}

test/unit/Common/Common.test.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"use strict";
2+
3+
require("should");
4+
import * as Common from "../../../src/Common";
5+
6+
describe("type guards HandlerFunction", () => {
7+
it("should compile the code", () => {
8+
const func = () => {};
9+
if (Common.isHandlerFunction(func)) {
10+
func();
11+
}
12+
});
13+
14+
it("should return true if function", () => {
15+
Common.isHandlerFunction(() => {}).should.be.true();
16+
});
17+
18+
it("should return false if not function", () => {
19+
Common.isHandlerFunction("MyHandler").should.be.false();
20+
});
21+
});

0 commit comments

Comments
 (0)