Last active
September 5, 2015 17:23
-
-
Save Leko/629003903fe856185977 to your computer and use it in GitHub Desktop.
Confine any process into transaction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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