@bitblit/epsilon
Version:
Tiny adapter to simplify building API gateway Lambda APIS
214 lines • 13 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EpsilonGlobalHandler = void 0;
const logger_1 = require("@bitblit/ratchet/common/logger");
const event_util_1 = require("./http/event-util");
const timeout_token_1 = require("@bitblit/ratchet/common/timeout-token");
const promise_ratchet_1 = require("@bitblit/ratchet/common/promise-ratchet");
const response_util_1 = require("./http/response-util");
const request_timeout_error_1 = require("./http/error/request-timeout-error");
const common_1 = require("@bitblit/ratchet/common");
const context_util_1 = require("./util/context-util");
const web_v2_handler_1 = require("./http/web-v2-handler");
const inter_api_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/inter-api-epsilon-lambda-event-handler");
const generic_sns_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/generic-sns-epsilon-lambda-event-handler");
const generic_sqs_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/generic-sqs-epsilon-lambda-event-handler");
const cron_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/cron-epsilon-lambda-event-handler");
const s3_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/s3-epsilon-lambda-event-handler");
const dynamo_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/dynamo-epsilon-lambda-event-handler");
const epsilon_logging_extension_processor_1 = require("./epsilon-logging-extension-processor");
const no_handlers_found_error_1 = require("./config/no-handlers-found-error");
/**
* This class functions as the adapter from a default Lambda function to the handlers exposed via Epsilon
*/
class EpsilonGlobalHandler {
static set globalInstanceProvider(input) {
EpsilonGlobalHandler.GLOBAL_INSTANCE_PROVIDER = input;
}
static get globalInstanceProvider() {
return EpsilonGlobalHandler.GLOBAL_INSTANCE_PROVIDER;
}
constructor(_epsilon) {
this._epsilon = _epsilon;
this.handlers = null;
// We only want to do this if it wasn't explicitly configured earlier
if (!EpsilonGlobalHandler.LOGGER_CONFIGURED) {
EpsilonGlobalHandler.configureDefaultLogger();
logger_1.Logger.info('EpsilonLoggingConfiguration:Default logger configured');
}
else {
logger_1.Logger.info('EpsilonLoggingConfiguration:Skipping default logger config - already configured');
}
this.handlers = [
this._epsilon.webHandler,
new web_v2_handler_1.WebV2Handler(this._epsilon.webHandler),
this._epsilon.backgroundHandler,
new inter_api_epsilon_lambda_event_handler_1.InterApiEpsilonLambdaEventHandler(this._epsilon),
new generic_sns_epsilon_lambda_event_handler_1.GenericSnsEpsilonLambdaEventHandler(this._epsilon),
new generic_sqs_epsilon_lambda_event_handler_1.GenericSqsEpsilonLambdaEventHandler(this._epsilon),
new cron_epsilon_lambda_event_handler_1.CronEpsilonLambdaEventHandler(this._epsilon),
new s3_epsilon_lambda_event_handler_1.S3EpsilonLambdaEventHandler(this._epsilon),
new dynamo_epsilon_lambda_event_handler_1.DynamoEpsilonLambdaEventHandler(this._epsilon),
];
}
static configureDefaultLogger(overrides) {
var _a, _b, _c, _d, _e;
const output = overrides ? Object.assign({}, overrides) : {};
output.initialLevel = (_a = output.initialLevel) !== null && _a !== void 0 ? _a : common_1.LoggerLevelName.info;
output.formatType = (_b = output.formatType) !== null && _b !== void 0 ? _b : common_1.LogMessageFormatType.StructuredJson;
//output.trace;
output.globalVars = (_c = output.globalVars) !== null && _c !== void 0 ? _c : {}; // No extra defaults for now
output.outputFunction = (_d = output.outputFunction) !== null && _d !== void 0 ? _d : common_1.LoggerOutputFunction.StdOut;
output.ringBufferSize = (_e = output.ringBufferSize) !== null && _e !== void 0 ? _e : 0;
const src = output.preProcessors || [];
output.preProcessors = src.concat([new epsilon_logging_extension_processor_1.EpsilonLoggingExtensionProcessor()]);
//output.preProcessors.push();
logger_1.Logger.info('EpsilonLoggingConfiguration: configureDefaultLogger: pre');
logger_1.Logger.dumpOptionsIntoLog();
logger_1.Logger.changeDefaultOptions(output, true);
logger_1.Logger.info('EpsilonLoggingConfiguration: configureDefaultLogger: post');
logger_1.Logger.dumpOptionsIntoLog();
EpsilonGlobalHandler.LOGGER_CONFIGURED = true;
logger_1.Logger.info('EpsilonLoggingConfiguration: Updated');
}
get defaultLoggerInstance() {
return logger_1.Logger.getLogger();
}
get epsilon() {
return this._epsilon;
}
processSingleBackgroundByParts(type, data, overrideTraceId, overrideTraceDepth) {
return __awaiter(this, void 0, void 0, function* () {
return this.processSingleBackgroundEntry(this._epsilon.backgroundManager.createEntry(type, data), overrideTraceId, overrideTraceDepth);
});
}
processSingleBackgroundEntry(e, overrideTraceId, overrideTraceDepth) {
return __awaiter(this, void 0, void 0, function* () {
let rval = false;
if (e === null || e === void 0 ? void 0 : e.type) {
const internal = yield this._epsilon.backgroundManager.wrapEntryForInternal(e, overrideTraceId, overrideTraceDepth);
rval = yield this._epsilon.backgroundHandler.processSingleBackgroundEntry(internal);
logger_1.Logger.info('Direct processed request %j to %s', e, rval);
}
else {
logger_1.Logger.error('Cannot process null/unnamed background entry');
}
return rval;
});
}
lambdaHandler(event, context) {
return __awaiter(this, void 0, void 0, function* () {
let rval = null;
try {
if (this.epsilon.config.disableLastResortTimeout || !context || !context.getRemainingTimeInMillis()) {
rval = yield this.innerLambdaHandler(event, context);
}
else {
// Outer wrap timeout makes sure that we timeout even if the slow part is a filter instead of the controller
const tmp = yield promise_ratchet_1.PromiseRatchet.timeout(this.innerLambdaHandler(event, context), 'EpsilonLastResortTimeout', context.getRemainingTimeInMillis() - 1000); // Reserve 1 second for cleanup
if (timeout_token_1.TimeoutToken.isTimeoutToken(tmp)) {
tmp.writeToLog();
// Using the HTTP version since it can use it, and the background ones dont care about the response format
rval = response_util_1.ResponseUtil.errorResponse(common_1.RestfulApiHttpError.wrapError(new request_timeout_error_1.RequestTimeoutError('Timed out')));
}
else {
rval = tmp;
}
}
}
finally {
context_util_1.ContextUtil.clearContext();
}
return rval;
});
}
innerLambdaHandler(event, context) {
var _a, _b, _c, _d, _e, _f;
return __awaiter(this, void 0, void 0, function* () {
context_util_1.ContextUtil.initContext(this._epsilon, event, context, 'TBD');
let rval = null;
let errorHandler = EpsilonGlobalHandler.defaultProcessUncaughtError;
let noMatchingHandler = false;
try {
if (!this._epsilon) {
logger_1.Logger.error('Config not found, abandoning');
return false;
}
// Setup logging
const logLevel = event_util_1.EventUtil.calcLogLevelViaEventOrEnvParam(logger_1.Logger.getLevel(), event, this._epsilon.config.loggerConfig);
logger_1.Logger.setLevel(logLevel);
if (this._epsilon.config.loggerConfig &&
this._epsilon.config.loggerConfig.queryParamTracePrefixName &&
event.queryStringParameters &&
event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]) {
logger_1.Logger.info('Setting trace prefix to %s', event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]);
logger_1.Logger.updateTracePrefix(event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]);
}
let found = false;
for (let i = 0; i < this.handlers.length && !found; i++) {
const handler = this.handlers[i];
if (handler.handlesEvent(event)) {
found = true;
errorHandler = handler.processUncaughtError || errorHandler; // Override it, if the handler supports that
const label = handler.extractLabel(event, context);
context_util_1.ContextUtil.setProcessLabel(label);
logger_1.Logger.logByLevel(((_c = (_b = (_a = this._epsilon) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b.loggerConfig) === null || _c === void 0 ? void 0 : _c.epsilonStartEndMessageLogLevel) || common_1.LoggerLevelName.info, 'EvtStart: %s', label);
try {
rval = yield handler.processEvent(event, context);
}
catch (err) {
if (err instanceof no_handlers_found_error_1.NoHandlersFoundError) {
// We found a generic handler to handle this event, but it didn't have any handlers for
// this specific message.
// Reset "found" flag to false, but still break the loop.
found = false;
break;
}
else {
throw err;
}
}
logger_1.Logger.logByLevel(((_f = (_e = (_d = this._epsilon) === null || _d === void 0 ? void 0 : _d.config) === null || _e === void 0 ? void 0 : _e.loggerConfig) === null || _f === void 0 ? void 0 : _f.epsilonStartEndMessageLogLevel) || common_1.LoggerLevelName.info, 'EvtEnd: %s', label);
logger_1.Logger.silly('EvtEnd:Value: %s Value: %j', label, rval);
}
}
if (!found) {
noMatchingHandler = true;
}
}
catch (err) {
// Note: If your errorHandler throws an error its just gonna get thrown up, which is what we want
// since some of them actually NEED to rethrow errors to get auto-retries (eg, Dynamo)
rval = yield errorHandler(event, context, err);
}
if (this.epsilon.config.throwErrorIfNoSuitableEventHandlers && noMatchingHandler) {
logger_1.Logger.error('No matching handler found for event: %j', event);
throw new Error('No matching handler found for event');
}
return rval;
});
}
static defaultProcessUncaughtError(event, context, err) {
return __awaiter(this, void 0, void 0, function* () {
logger_1.Logger.error('Error slipped out to outer edge (Default). Logging and returning log : %s', err, err);
const rval = {
statusCode: 500,
body: JSON.stringify({ error: common_1.ErrorRatchet.safeStringifyErr(err) }),
isBase64Encoded: false,
};
return rval;
});
}
}
exports.EpsilonGlobalHandler = EpsilonGlobalHandler;
EpsilonGlobalHandler.LOGGER_CONFIGURED = false;
//# sourceMappingURL=epsilon-global-handler.js.map