-
Notifications
You must be signed in to change notification settings - Fork 63
/
Copy pathfunctionRunner.ts
120 lines (110 loc) · 3.58 KB
/
functionRunner.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { ServerlessCallback } from '@twilio-labs/serverless-runtime-types/types';
import { serializeError } from 'serialize-error';
import {
augmentContextWithOptionals,
constructContext,
constructGlobalScope,
isTwiml,
} from '../route';
import { ServerConfig, Headers } from '../types';
import { CrossForkLogger } from './crossForkLogger';
import { Response } from './response';
import { setRoutes } from './route-cache';
const sendDebugMessage = (debugMessage: string, ...debugArgs: any) => {
process.send && process.send({ debugMessage, debugArgs });
};
export type Reply = {
body?: string | number | boolean | object;
headers?: Headers;
statusCode: number;
};
export type FunctionRunnerOptions = {
functionPath: string;
event: { [key: string]: any };
config: ServerConfig;
path: string;
};
const handleError = (err: Error | string | object) => {
if (err) {
process.send && process.send({ err: serializeError(err) });
}
};
const handleSuccess = (responseObject?: string | number | boolean | object) => {
let reply: Reply = { statusCode: 200 };
if (typeof responseObject === 'string') {
sendDebugMessage('Sending basic string response');
reply.headers = { 'Content-Type': 'text/plain' };
reply.body = responseObject;
} else if (
responseObject &&
typeof responseObject === 'object' &&
isTwiml(responseObject)
) {
sendDebugMessage('Sending TwiML response as XML string');
reply.headers = { 'Content-Type': 'text/xml' };
reply.body = responseObject.toString();
} else if (responseObject && responseObject instanceof Response) {
sendDebugMessage('Sending custom response');
reply = responseObject.serialize();
} else {
sendDebugMessage('Sending JSON response');
reply.body = responseObject;
reply.headers = { 'Content-Type': 'application/json' };
}
if (process.send) {
process.send({ reply });
}
};
process.on('uncaughtException', (err, origin) => {
if (process.send) {
process.send({ err: serializeError(err) });
}
});
process.on(
'message',
({ functionPath, event, config, path }: FunctionRunnerOptions) => {
try {
setRoutes(config.routes);
constructGlobalScope(config);
config.logger = new CrossForkLogger();
let context = constructContext(config, path);
sendDebugMessage('Context for %s: %p', path, context);
context = augmentContextWithOptionals(config, context);
sendDebugMessage('Event for %s: %o', path, event);
let run_timings: { start: [number, number]; end: [number, number] } = {
start: [0, 0],
end: [0, 0],
};
const callback: ServerlessCallback = (err, responseObject) => {
run_timings.end = process.hrtime();
sendDebugMessage('Function execution %s finished', path);
sendDebugMessage(
`(Estimated) Total Execution Time: ${
(run_timings.end[0] * 1e9 +
run_timings.end[1] -
(run_timings.start[0] * 1e9 + run_timings.start[1])) /
1e6
}ms`
);
if (err) {
handleError(err);
} else {
handleSuccess(responseObject);
}
};
sendDebugMessage('Calling function for %s', path);
run_timings.start = process.hrtime();
const { handler } = require(functionPath);
if (typeof handler !== 'function') {
throw new Error(
`Could not find a "handler" function in file ${functionPath}`
);
}
handler(context, event, callback);
} catch (err) {
if (process.send) {
process.send({ err: serializeError(err) });
}
}
}
);