@bitblit/ratchet-common
Version:
Common tools for general use
77 lines • 3.52 kB
JavaScript
import { Logger } from '../logger/logger.js';
import { RequireRatchet } from '../lang/require-ratchet.js';
import { LoggerLevelName } from '../logger/logger-level-name.js';
import { TransactionFinalState } from './transaction-final-state.js';
export class TransactionRatchet {
static async execute(steps, initialContext, inConfiguration) {
RequireRatchet.notNullOrUndefined(steps, 'steps');
RequireRatchet.notNullOrUndefined(initialContext, 'initialContext');
RequireRatchet.true(steps.length > 0, 'steps may not be empty');
const config = Object.assign({}, inConfiguration || {});
config.stepLogLevel = config.stepLogLevel || LoggerLevelName.info;
const rval = {
finalContext: initialContext,
finalState: null,
};
const stepNames = steps.map((s, idx) => s.name || 'Step ' + idx);
Logger.info('Beginning transaction of %d steps', steps.length);
let idx = 0;
do {
Logger.logByLevel(config.stepLogLevel, 'Processing step %d of %d (%s)', idx + 1, steps.length, stepNames[idx]);
try {
await steps[idx].execute(rval.finalContext, idx);
idx++;
}
catch (err) {
Logger.error('Failure detected on step %d : %s : %s : Rolling back', idx, stepNames[idx], err, err);
rval.error = err;
rval.errorStep = idx;
}
} while (!rval.error && idx < steps.length);
if (rval.error) {
do {
Logger.logByLevel(config.stepLogLevel, 'Rolling back step %d of %d (%s)', idx + 1, steps.length, stepNames[idx]);
try {
if (steps[idx].rollback) {
await steps[idx].rollback(rval.finalContext, idx);
}
else {
Logger.info('Skipping - no rollback defined');
}
}
catch (err) {
Logger.error('Very bad - rollback code failed on step %d : %s : Aborting in invalid state: %s', idx, stepNames[idx], err, err);
rval.rollbackError = err;
rval.rollbackErrorStep = idx;
}
idx--;
} while (idx >= 0);
}
rval.finalState = rval.rollbackError
? TransactionFinalState.RollbackFailed
: rval.error
? TransactionFinalState.RolledBack
: TransactionFinalState.Success;
Logger.info('Transaction completed with status : %s', rval.finalState);
if (config?.executeAfterRollback && rval.finalState !== TransactionFinalState.Success) {
try {
Logger.info('Applying executeAfterRollback');
await config.executeAfterRollback(rval);
}
catch (err) {
Logger.error('Very bad - failure in executeAfterRollback : %s', err, err);
}
}
if (config?.executeAfterRollbackFailure && rval.finalState !== TransactionFinalState.Success) {
try {
Logger.info('Applying executeAfterRollbackFailure');
await config.executeAfterRollbackFailure(rval);
}
catch (err) {
Logger.error('Very bad - failure in executeAfterRollbackFailure : %s', err, err);
}
}
return rval;
}
}
//# sourceMappingURL=transaction-ratchet.js.map