Skip to content

Instantly share code, notes, and snippets.

@Leko
Last active September 5, 2015 17:23
Show Gist options
  • Save Leko/629003903fe856185977 to your computer and use it in GitHub Desktop.
Save Leko/629003903fe856185977 to your computer and use it in GitHub Desktop.
Confine any process into transaction
'use strict';
var Integrity = require('./integrity'),
Transaction = Integrity.Transaction,
Action = Integrity.Action;
function add(target, num) {
return function() { target.num += num; };
}
function asyncAdd(target, num) {
return function(done) { setTimeout(function() { add(target, num)(); done(); }, 50); };
}
function sub(target, num) {
return function() { target.num -= num; };
}
function asyncSub(target, num) {
return function(done) { setTimeout(function() { sub(target, num)(); done(); }, 50); };
}
function debug(target) {
return function() { console.log('debug:', target); };
}
function fail() {
throw new Error('Failure!!');
}
function case1() {
console.log("--- case 1. success --------------------------------------------");
var state = { num: 1 };
var t = Transaction.begin();
t.then(new Action(asyncAdd(state, 1), sub(state, 1)))
.then(new Action(debug(state)))
.then(new Action(add(state, 3), asyncSub(state, 3)))
.then(new Action(debug(state)))
.commit()
.then(function() {
console.log('success:', state);
case2();
})
.catch(function(e) {
console.log('failed:', e);
console.log('before rollback:', state);
t.rollback();
console.log('after rollback:', state);
case2();
});
}
function case2() {
console.log("--- case 2. failed --------------------------------------------");
var state = {
num: 1
};
var t = Transaction.begin();
t.then(new Action(add(state, 1), asyncSub(state, 1)))
.then(new Action(debug(state)))
.then(new Action(asyncAdd(state, 2), sub(state, 2)))
.then(new Action(debug(state)))
.then(new Action(asyncAdd(state, 3), asyncSub(state, 3)))
.then(new Action(debug(state)))
.then(new Action(fail))
.then(new Action(debug(state))) // Not executed
.commit()
.then(function() {
console.log('success:', state);
})
.catch(function(e) {
console.log('failed:', e);
console.log('before rollback:', state);
t.rollback();
console.log('after rollback:', state);
});
}
case1();
// $ node demo.js
// --- case 1. success --------------------------------------------
// debug: { num: 2 }
// debug: { num: 5 }
// success: { num: 5 }
// --- case 2. failed --------------------------------------------
// debug: { num: 2 }
// debug: { num: 4 }
// debug: { num: 7 }
// failed: [Error: Failure!!]
// before rollback: { num: 7 }
// after rollback: { num: 1 }
// More
// - [cowboy/bad-bad-bad.js](https://gist.github.com/cowboy/1289665)
// - [process Node.js v0.12.7 Manual & Documentation](https://nodejs.org/api/process.html)
'use strict';
function noop() {}
function anySyncCall(func, then) {
if(func.length >= 1) {
func(then);
} else {
func();
then();
}
}
var Transaction = (function() {
function Transaction() {
this.transactions = [];
this.done = [];
}
Transaction.begin = function() {
return new Transaction();
}
Transaction.prototype = {
then: function(transaction) {
this.transactions.push(transaction);
return this;
},
commit: function() {
var process = function(resolve, reject) {
if(this.transactions.length <= 0) resolve();
var action = this.transactions.shift();
try {
anySyncCall(action.action, process.bind(this, resolve, reject));
this.done.push(action);
} catch(e) {
reject(e);
}
}.bind(this);
var promise = new Promise(process);
return promise;
},
rollback: function() {
if(this.done.length <= 0) return;
var action = this.done.pop();
anySyncCall(action.failback, this.rollback.bind(this));
}
};
return Transaction;
}());
var Action = (function() {
function Action(action, failback) {
if(typeof action !== 'function') {
throw new TypeError('action must be function');
}
if(typeof failback !== 'function') {
failback = noop;
}
this.action = action;
this.failback = failback;
}
return Action;
}());
module.exports = {
Transaction: Transaction,
Action: Action,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment