@deliverr/serverless-offline-step-functions
Version:
Serverless Offline Plugin to Support Step Functions for Local Development
118 lines (117 loc) • 6.32 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MapExecutor = void 0;
const lodash_chunk_1 = __importDefault(require("lodash.chunk"));
const StateTypeExecutor_1 = require("../StateTypeExecutor");
const StateMachineExecutor_1 = require("../../StateMachineExecutor");
const StateContext_1 = require("../../Context/StateContext");
const StateProcessor_1 = require("../../StateProcessor");
const StateMachine_1 = require("../../StateMachine/StateMachine");
const Logger_1 = require("../../utils/Logger");
class MapExecutor extends StateTypeExecutor_1.StateTypeExecutor {
constructor() {
super(...arguments);
this.pendingStateMachineExecutions = {};
}
async execute(context, stateDefinition, inputJson) {
const stateMachineDescription = {
name: stateDefinition.Comment,
definition: stateDefinition.Iterator,
};
const stateMachine = StateMachine_1.StateMachine.create(stateMachineDescription.name || '', stateMachineDescription);
if (!inputJson) {
throw new Error(`Undefined inputJson for state `);
}
const iterable = this.processInput(inputJson, stateDefinition, context);
const iterableOutputPromises = iterable.map(async (value, index) => {
const tempContext = context.clone();
const iterationInputValue = typeof value === 'string' ? value : JSON.stringify(value);
tempContext.startMapItration(index, iterationInputValue);
const iterationInput = StateProcessor_1.StateProcessor.processParameters(iterationInputValue, stateDefinition.Parameters, tempContext);
const stateName = stateDefinition.Iterator.StartAt;
const stateContext = StateContext_1.StateContext.create(stateName);
tempContext.transitionTo(stateContext);
const sme = new StateMachineExecutor_1.StateMachineExecutor(stateMachine, tempContext);
const startAtState = stateDefinition.Iterator.States[stateDefinition.Iterator.StartAt];
const execution = await sme.execute(startAtState, iterationInput);
if (execution instanceof StateMachineExecutor_1.StateMachineExecutorError) {
throw execution.error;
}
return typeof execution === 'string' ? JSON.parse(execution) : execution;
});
const maxConcurrency = stateDefinition.MaxConcurrency || 0;
let iterableOutput = [];
if (maxConcurrency <= 0) {
this.logger.log('Running Map iterables in Parallel');
iterableOutput = await Promise.all(iterableOutputPromises);
}
else {
this.logger.log(`Running Map iterables in chunks of ${maxConcurrency}`);
const promiseChunks = lodash_chunk_1.default(iterableOutputPromises, maxConcurrency);
for (let index = 0; index < promiseChunks.length; index++) {
const promisechunk = promiseChunks[index];
this.logger.log(`Running Map iterable chunk (${index + 1}/${promiseChunks.length})`);
const result = await Promise.all(promisechunk);
iterableOutput.push(...result);
}
}
this.logger.debug('Finished processing iterable');
this.logger.debug(JSON.stringify(iterableOutput));
const output = this.processOutput(JSON.parse(inputJson), iterableOutput, stateDefinition);
return {
Next: stateDefinition.Next,
End: stateDefinition.End,
json: JSON.stringify(output),
};
}
processOutput(input, output, stateDefinition) {
this.logger.debug(`MapExecutor - processOutput - stepOutputJSON - input`);
this.logger.debug(typeof input);
this.logger.debug(JSON.stringify(input));
this.logger.debug(`MapExecutor - processOutput - stepOutputJSON - output`);
this.logger.debug(JSON.stringify(output));
this.logger.debug(typeof output);
let stepOutputJSON = StateProcessor_1.StateProcessor.processResultSelector(JSON.stringify(output), stateDefinition.ResultSelector);
stepOutputJSON = StateProcessor_1.StateProcessor.processResultPath(input, JSON.parse(stepOutputJSON), stateDefinition.ResultPath);
this.logger.debug(stepOutputJSON);
const outputJson = StateProcessor_1.StateProcessor.processOutputPath(stepOutputJSON, stateDefinition.OutputPath);
this.logger.debug(outputJson);
let processedOutput;
try {
processedOutput = JSON.parse(outputJson);
this.logger.debug(`processedOutput`);
this.logger.debug(typeof processedOutput);
}
catch (error) {
this.logger.error(`MapExecutor.processInput: Could not parse JSON: "${outputJson}"`);
throw error;
}
return processedOutput;
}
processInput(json, stateDefinition, context) {
this.logger.debug(`MapExecutor - processInput1 - ${json}`);
const processedInputJson = StateProcessor_1.StateProcessor.processInputPath(json, stateDefinition.InputPath);
const processedItemsJson = StateProcessor_1.StateProcessor.processItemsPath(processedInputJson, stateDefinition.ItemsPath);
let processedItems;
try {
processedItems = JSON.parse(processedItemsJson);
}
catch (error) {
this.logger.error(`MapExecutor.processInput: Could not parse JSON for state ${context.State.Name}: "${processedItemsJson}"`);
throw error;
}
if (!Array.isArray(processedItems)) {
this.logger.error('Processed input & items is not an array ' +
`with InputPath: ${stateDefinition.InputPath} & ItemsPaths: ${stateDefinition.ItemsPath} and input: ${json}`);
throw new Error('Input is not an array');
}
Logger_1.Logger.getInstance().debug('Finished processing Map input');
Logger_1.Logger.getInstance().debug(JSON.stringify(processedItems));
Logger_1.Logger.getInstance().debug(typeof processedItems[0]);
return processedItems;
}
}
exports.MapExecutor = MapExecutor;