UNPKG

@mbc-cqrs-serverless/core

Version:
217 lines 9.81 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var CommandEventHandler_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.CommandEventHandler = void 0; const common_1 = require("@nestjs/common"); const config_1 = require("@nestjs/config"); const sfn_name_enum_1 = require("../command-events/sfn-name.enum"); const data_store_1 = require("../data-store"); const key_1 = require("../helpers/key"); const queue_1 = require("../queue"); const step_function_service_1 = require("../step-func/step-function.service"); const command_module_definition_1 = require("./command.module-definition"); const command_service_1 = require("./command.service"); const data_service_1 = require("./data.service"); const status_enum_1 = require("./enums/status.enum"); const history_service_1 = require("./history.service"); let CommandEventHandler = CommandEventHandler_1 = class CommandEventHandler { constructor(options, commandService, dataService, historyService, s3Service, snsService, config, sfnService) { this.options = options; this.commandService = commandService; this.dataService = dataService; this.historyService = historyService; this.s3Service = s3Service; this.snsService = snsService; this.config = config; this.sfnService = sfnService; this.logger = new common_1.Logger(`${CommandEventHandler_1.name}:${this.options.tableName}`); this.alarmTopicArn = this.config.get('SNS_ALARM_TOPIC_ARN'); } async execute(event) { this.logger.debug('executing::', event); await this.commandService.updateStatus(event.commandKey, (0, status_enum_1.getCommandStatus)(event.stepStateName, status_enum_1.CommandStatus.STATUS_STARTED), event.commandRecord.requestId); try { const ret = await this.handleStepState(event); await this.commandService.updateStatus(event.commandKey, (0, status_enum_1.getCommandStatus)(event.stepStateName, status_enum_1.CommandStatus.STATUS_FINISHED), event.commandRecord.requestId); return ret; } catch (error) { await this.commandService.updateStatus(event.commandKey, (0, status_enum_1.getCommandStatus)(event.stepStateName, status_enum_1.CommandStatus.STATUS_FAILED), event.commandRecord.requestId); await this.publishAlarm(event, error.stack); throw error; } } async handleStepState(event) { switch (event.stepStateName) { case sfn_name_enum_1.DataSyncCommandSfnName.CHECK_VERSION: return await this.checkVersion(event); case sfn_name_enum_1.DataSyncCommandSfnName.WAIT_PREV_COMMAND: return await this.waitConfirmToken(event); case sfn_name_enum_1.DataSyncCommandSfnName.SET_TTL_COMMAND: return await this.setTtlCommand(event); case sfn_name_enum_1.DataSyncCommandSfnName.HISTORY_COPY: return await this.historyCopy(event); case sfn_name_enum_1.DataSyncCommandSfnName.TRANSFORM_DATA: return await this.transformData(event); case sfn_name_enum_1.DataSyncCommandSfnName.SYNC_DATA: return await this.syncData(event); case sfn_name_enum_1.DataSyncCommandSfnName.FINISH: return await this.checkNextToken(event); default: throw new Error('step function state not found!'); } } async waitConfirmToken(event) { this.logger.debug('waitConfirmToken::', event); await this.commandService.updateTaskToken(event.commandKey, event.taskToken); return { result: { token: event.taskToken, }, }; } async checkVersion(event) { this.logger.debug('Checking version::', event.commandRecord); const sk = (0, key_1.removeSortKeyVersion)(event.commandRecord.sk); const data = await this.dataService.getItem({ pk: event.commandRecord.pk, sk, }); this.logger.debug('Checking version for data::', data); const commandVersion = event.commandRecord.version; const nextVersion = 1 + (data?.version || 0); const oldCommand = await this.commandService.getItem({ pk: event.commandRecord.pk, sk: (0, key_1.addSortKeyVersion)(sk, commandVersion - 1), }); if (nextVersion === commandVersion) { return { result: 0, }; } if (nextVersion < commandVersion) { if (!oldCommand) { return { result: 0, }; } // wait for previous version is stable return { result: 1, }; } const errorDetails = { result: -1, error: 'version is not match', cause: 'next version must be ' + nextVersion + ' but got ' + commandVersion, }; await this.publishAlarm(event, errorDetails); return errorDetails; } async setTtlCommand(event) { this.logger.debug('setTtlCommand:: ', event.commandRecord); await this.commandService.updateTtl({ pk: event.commandRecord.pk, sk: event.commandRecord.sk, }); return { result: 'ok', }; } async historyCopy(event) { this.logger.debug('historyCopy:: ', event.commandRecord); await this.historyService.publish({ pk: event.commandRecord.pk, sk: (0, key_1.removeSortKeyVersion)(event.commandRecord.sk), }); return { result: 'ok', }; } async transformData(event) { this.logger.debug('transformData:: ', event.commandRecord); return this.commandService.dataSyncHandlers.map((cls) => ({ prevStateName: event.stepStateName, result: cls.constructor.name, })); } async syncData(event) { this.logger.debug('syncData:: ', event.commandRecord); const handlerName = event.input?.result; if (!handlerName) { throw new Error('SyncDataHandler not found!'); } const handler = this.commandService.getDataSyncHandler(handlerName); if (!handler) { throw new Error('SyncDataHandler empty!'); } const commandModel = await event.getFullCommandRecord(this.s3Service); return handler.up(commandModel); } async checkNextToken(event) { this.logger.debug('checkNextToken:: ', event.commandRecord); const nextCommand = await this.commandService.getNextCommand(event.commandKey); if (!nextCommand) { this.logger.debug('No next command version found. Chain ends.'); return null; } if (nextCommand.taskToken) { this.logger.log(`Found waiting command v${nextCommand.version}. Resuming...`); try { await this.sfnService.resumeExecution(nextCommand.taskToken, { result: 'resumed_by_prev_version', prevVersion: event.commandRecord.version, }); } catch (e) { this.logger.warn(`Could not resume command v${nextCommand.version}: ${e instanceof Error ? e.message : 'Unknown error'}`); } } else { this.logger.warn(`Next command v${nextCommand.version} found but no token. Status: ${nextCommand.status}`); } return null; } async publishAlarm(event, errorDetails) { this.logger.debug('event', event); const alarm = { action: 'sfn-alarm', id: `${event.commandKey.pk}#${event.commandKey.sk}`, table: this.options.tableName, pk: event.commandKey.pk, sk: event.commandKey.sk, tenantCode: event.commandKey.pk.substring(event.commandKey.pk.indexOf('#') + 1), content: { errorMessage: errorDetails, sfnId: event.context.Execution.Id, }, }; this.logger.error('alarm:::', alarm); await this.snsService.publish(alarm, this.alarmTopicArn); } }; exports.CommandEventHandler = CommandEventHandler; exports.CommandEventHandler = CommandEventHandler = CommandEventHandler_1 = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)(command_module_definition_1.MODULE_OPTIONS_TOKEN)), __metadata("design:paramtypes", [Object, command_service_1.CommandService, data_service_1.DataService, history_service_1.HistoryService, data_store_1.S3Service, queue_1.SnsService, config_1.ConfigService, step_function_service_1.StepFunctionService]) ], CommandEventHandler); //# sourceMappingURL=command.event.handler.js.map