@felloh-org/lambda-wrapper 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.yml +2 -0
- package/dist/config/dependencies.js +32 -0
- package/dist/dependency-injection/dependency-aware.js +43 -0
- package/dist/dependency-injection/dependency-injection.js +135 -0
- package/dist/index.js +113 -0
- package/dist/model/index.js +45 -0
- package/dist/model/response/index.js +150 -0
- package/dist/model/status/index.js +82 -0
- package/dist/service/http.js +55 -0
- package/dist/service/logger.js +236 -0
- package/dist/service/request.js +342 -0
- package/dist/util/lambda-termination.js +39 -0
- package/dist/util/promisified-delay.js +59 -0
- package/dist/wrapper/index.js +165 -0
- package/package.json +1 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.handleSuccess = exports.handleError = exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _epsagon = _interopRequireDefault(require("epsagon"));
|
|
9
|
+
|
|
10
|
+
var _dependencies = require("../config/dependencies");
|
|
11
|
+
|
|
12
|
+
var _dependencyInjection = _interopRequireDefault(require("../dependency-injection/dependency-injection"));
|
|
13
|
+
|
|
14
|
+
var _response = _interopRequireDefault(require("../model/response"));
|
|
15
|
+
|
|
16
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
|
+
|
|
18
|
+
/* eslint-disable sonarjs/cognitive-complexity */
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Processes the outcome once we have one
|
|
22
|
+
*
|
|
23
|
+
* @param di
|
|
24
|
+
* @param outcome
|
|
25
|
+
*/
|
|
26
|
+
const handleSuccess = (di, outcome) => {
|
|
27
|
+
const logger = di.get(_dependencies.DEFINITIONS.LOGGER); // Outcome may be undefined as not all lambdas have a return value.
|
|
28
|
+
|
|
29
|
+
logger.metric('lambda.statusCode', outcome && outcome.statusCode || 200);
|
|
30
|
+
return outcome;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Gracefully handles an error
|
|
34
|
+
* logging in Epsagon and generating
|
|
35
|
+
* a response reflecting the `code`
|
|
36
|
+
* of the error, if defined.
|
|
37
|
+
*
|
|
38
|
+
* Note about Epsagon:
|
|
39
|
+
* Epsagon generates alerts for logs on level ERROR.
|
|
40
|
+
* This means that logger.error will produce an alert.
|
|
41
|
+
* To avoid not meaningful notifications, most likely
|
|
42
|
+
* coming from tests, we log INFO unless either:
|
|
43
|
+
*
|
|
44
|
+
* 1. `error.raiseOnEpsagon` is defined & truthy
|
|
45
|
+
* 2. `error.code` is defined and `error.code >= 500`.
|
|
46
|
+
*
|
|
47
|
+
* @param {DependencyInjection} di
|
|
48
|
+
* @param {Error} error
|
|
49
|
+
* @param {boolean} [throwError=false]
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
exports.handleSuccess = handleSuccess;
|
|
54
|
+
|
|
55
|
+
const handleError = (di, error, throwError = false) => {
|
|
56
|
+
const logger = di.get(_dependencies.DEFINITIONS.LOGGER);
|
|
57
|
+
logger.metric('lambda.statusCode', error.code || 500);
|
|
58
|
+
|
|
59
|
+
if (error.raiseOnEpsagon || !error.code || error.code >= 500) {
|
|
60
|
+
logger.error(error);
|
|
61
|
+
} else {
|
|
62
|
+
logger.info(error);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (throwError) {
|
|
66
|
+
if (error instanceof Error) {
|
|
67
|
+
return error;
|
|
68
|
+
} // We want to be absolutely sure
|
|
69
|
+
// that we are returning an error
|
|
70
|
+
// as Lambda sync handlers will only fail
|
|
71
|
+
// if the object is instanceof Error
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
return new Error(error);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const responseDetails = {
|
|
78
|
+
body: error.body || {},
|
|
79
|
+
code: error.code || 500,
|
|
80
|
+
details: error.details || 'unknown error'
|
|
81
|
+
};
|
|
82
|
+
return _response.default.generate(responseDetails.body, responseDetails.code, responseDetails.details);
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Lambda Wrapper.
|
|
86
|
+
*
|
|
87
|
+
* Wraps a lambda handler, generating a new function
|
|
88
|
+
* that has access to the dependency injection
|
|
89
|
+
* for the service and handles logging and exceptions.
|
|
90
|
+
*
|
|
91
|
+
* @param configuration
|
|
92
|
+
* @param handler
|
|
93
|
+
* @param throwError
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
exports.handleError = handleError;
|
|
98
|
+
|
|
99
|
+
const wrapper = (configuration, handler, throwError = false) => {
|
|
100
|
+
let instance = (event, context, callback) => {
|
|
101
|
+
const di = new _dependencyInjection.default(configuration, event, context);
|
|
102
|
+
const request = di.get(_dependencies.DEFINITIONS.REQUEST);
|
|
103
|
+
const logger = di.get(_dependencies.DEFINITIONS.LOGGER);
|
|
104
|
+
context.callbackWaitsForEmptyEventLoop = false; // If the event is to trigger a warm up, then don't bother returning the function.
|
|
105
|
+
|
|
106
|
+
if (di.getEvent().source === 'serverless-plugin-warmup') {
|
|
107
|
+
return callback(null, 'Lambda is warm!');
|
|
108
|
+
} // Log the users ip address silently for use in error tracing
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if (request.getIp() !== null) {
|
|
112
|
+
logger.metric('ipAddress', request.getIp(), true);
|
|
113
|
+
} // Add metrics with user browser information for rapid debugging
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
const userBrowserAndDevice = request.getUserBrowserAndDevice();
|
|
117
|
+
|
|
118
|
+
if (userBrowserAndDevice !== null && typeof userBrowserAndDevice === 'object') {
|
|
119
|
+
Object.keys(userBrowserAndDevice).forEach(metricKey => {
|
|
120
|
+
logger.metric(metricKey, userBrowserAndDevice[metricKey], true);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let outcome;
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
outcome = handler.call(instance, di, request, callback);
|
|
128
|
+
|
|
129
|
+
if (outcome instanceof Promise) {
|
|
130
|
+
outcome = outcome.then(value => handleSuccess(di, value)).catch(error => {
|
|
131
|
+
const handled = handleError(di, error, throwError);
|
|
132
|
+
|
|
133
|
+
if (throwError) {
|
|
134
|
+
// AWS Lambda with async handler is looking for a rejection
|
|
135
|
+
// and not an error object directly
|
|
136
|
+
// and will treat resolved errors as successful
|
|
137
|
+
// as it will cast the error to JSON, i.e. `{}`
|
|
138
|
+
return Promise.reject(handled);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return handled;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
outcome = handleError(di, error, throwError);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return outcome;
|
|
149
|
+
}; // If the Epsagon token is enabled, then wrap the instance in the Epsagon wrapper
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
if (typeof process.env.EPSAGON_TOKEN === 'string' && process.env.EPSAGON_TOKEN !== 'undefined' && typeof process.env.EPSAGON_SERVICE_NAME === 'string' && process.env.EPSAGON_SERVICE_NAME !== 'undefined') {
|
|
153
|
+
_epsagon.default.init({
|
|
154
|
+
token: process.env.EPSAGON_TOKEN,
|
|
155
|
+
appName: process.env.EPSAGON_SERVICE_NAME
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
instance = _epsagon.default.lambdaWrapper(instance);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return instance;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
var _default = wrapper;
|
|
165
|
+
exports.default = _default;
|