UNPKG

@bitblit/ratchet-common

Version:

Common tools for general use

77 lines 3.52 kB
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