Created
August 25, 2013 14:07
-
-
Save luckydrq/6334033 to your computer and use it in GitHub Desktop.
mo publish操作的并发任务优化
This file contains 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
var Q = require('q') | |
var _ = require('underscore') | |
var exec = require('child_process').exec | |
var path = require('path') | |
var fs = require('fs') | |
//模拟Express App: `get`、`set` | |
var app = { | |
_data:{}, | |
get: function(key){ | |
return this._data[key] | |
}, | |
set: function(key, value){ | |
this._data[key] = value | |
} | |
} | |
app.set('tasks', []) | |
//模拟并发请求 | |
var CONCURRENT_REQUESTS = 10 | |
for (var i = 0; i < CONCURRENT_REQUESTS; i++) { | |
var task = createTask() | |
task.run() | |
}; | |
function createTask(){ | |
var id = _.uniqueId('task_') | |
var tasks = app.get('tasks') | |
tasks.push(id) | |
return { | |
id: id, | |
//执行所有任务操作 | |
run: function(){ | |
var self = this | |
//检查当前任务是否允许执行 | |
//当上一个任务完成了git_Step1(提交到本地repo),才允许开始执行下一个任务。 | |
Q.fcall(function(){ | |
var d = Q.defer() | |
function check(){ | |
if(id !== tasks[0]){ | |
setImmediate(check) | |
} | |
else{ | |
console.log('%s: Permitted', id) | |
d.resolve() | |
} | |
} | |
check() | |
return d.promise | |
}) | |
//执行git_Step1,视为原子操作 | |
.then(function(){ | |
return Q | |
.fcall(function(){ | |
return cleanup() | |
}) | |
.then(function(){ | |
if(fs.existsSync(vpath)){ | |
var oldVersion = parseInt(fs.readFileSync(vpath, {encoding: 'utf-8'}), 10) | |
self.gitVersion = version = ++oldVersion | |
fs.writeFileSync(vpath,version + '') | |
} | |
}) | |
.then(function(){ | |
return git_Step1(self) | |
}) | |
.fail(function(err){ | |
cleanup() | |
if(err) throw err | |
}) | |
.fin(function(){ | |
//执行完毕后释放 | |
tasks.shift() | |
}) | |
}) | |
//执行git_Step2,耗时操作,并发执行 | |
.then(function(){ | |
return git_Step2(self) | |
}) | |
.fail(function(err){ | |
if(err) console.log(err.message) | |
}) | |
} | |
} | |
} | |
var vpath = path.join(__dirname, 'VERSION') | |
var version | |
//Step1: 提交到本地repo | |
//可视为原子操作,不能并发,否则会搞乱。 | |
//而且,这些操作耗时很少,one by one执行没有降低太多效率 | |
function git_Step1(task){ | |
//Simplely use id as file name | |
var id = task.id | |
var version = task.gitVersion | |
var file = id | |
console.log('%s: Start git step1', id) | |
return Q | |
.fcall(run('echo "' + Math.random() + '" > ' + file)) | |
.then(run('git add -A')) | |
.then(run('git cm -m "update ' + file + '"')) | |
.fail(function(err){ | |
if(err) throw err | |
}) | |
.fin(function(){ | |
console.log('%s: Finish git step1', id) | |
}) | |
} | |
//Step2: 上传CDN | |
//耗时操作,允许多任务并发执行以提高效率 | |
//这些操作是互不影响的 | |
function git_Step2(task){ | |
var id = task.id | |
var version = task.gitVersion | |
return Q | |
.fcall(function(){ | |
console.log('%s: Start git step2', id) | |
}) | |
.then(run('git checkout -b daily/' + version)) | |
.then(run('git push origin daily/' + version)) | |
.then(run('git tag publish/' + version)) | |
.then(run('git push origin publish/' + version)) | |
.fail(function(err){ | |
if(err) throw err | |
}) | |
.fin(function(){ | |
console.log('%s: Finish git step2', id) | |
}) | |
} | |
/*********************************************************/ | |
function run(cmd, cwd) { | |
return function() { | |
return doRun(cmd, cwd) | |
} | |
} | |
function doRun(cmd, cwd) { | |
var d = Q.defer() | |
process.nextTick(function() { | |
d.notify(cmd + '\n') | |
}) | |
var proc = exec(cmd, { cwd: cwd || '.' }) | |
var successData = '' | |
var errorData = '' | |
proc.on('close', function(code) { | |
if (code === 0) { | |
d.resolve(successData) | |
} | |
else { | |
console.log(code, errorData) | |
d.reject(new Error(errorData)) | |
} | |
}) | |
proc.stderr.on('data', function(data) { | |
d.notify(data) | |
errorData += data | |
}) | |
proc.stdout.on('data', function(data) { | |
d.notify(data) | |
successData += data | |
}) | |
return d.promise | |
} | |
function cleanup(){ | |
return Q | |
.fcall(run('git reset HEAD --hard')) | |
.then(run('git clean -d -f')) | |
.then(run('git checkout master')) | |
.then(run('git pull origin master')) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment