我正在使用fast-csv使用stream
迭代CSV文件。对于CSV文件的每一行,我想在redis中创建一个作业,我使用kue。解析一行是同步函数。整件事看起来像这样:
var csvStream = fastCsv(_config.csvOptions)
.on('data', function(data) {
var stream = this;
stream.pause();
var payload = parseRow(data, _config);
console.log(payload); // the payload is always printed to the console
var job = kue.create('csv-row', {
payload: payload
})
.save(function(err) {
if (!err) console.log('Enqueued at ' + job.id);
else console.log('Redis error ' + JSON.stringify(err));
stream.resume();
});
})
.on('end', function() {
callback(); // this ends my parsing
});
我的CSV文件的每一行都显示简单console.log(payload);
,但未创建作业。即,save
回调中的所有输出都没有打印出来,而且作业不在我的redis中。
我认为,因为它是CSV文件的最后一行,所以流已经发出end
,因此在流程终止之前无法执行最后一个kue.create()
?
有没有办法暂停流end
直到kue完成?
答案 0 :(得分:6)
您可以使用async library解决此问题。您可以将以下模式用于任何流。
var AsyncLib = require('async');
var worker = function (payload, cb) {
//do something with payload and call callback
return cb();
};
var concurrency = 5;
var streamQueue = AsyncLib.queue(worker, concurrency);
var stream = //some readable stream;
stream.on('data', function(data) {
//no need to pause and resume
var payload = '//some payload';
streamQueue.push(payload);
})
.on('end', function() {
//register drain event on end and callback
streamQueue.drain = function () {
callback();
};
});
答案 1 :(得分:4)
我刚刚发现自己处于同样的境地。我用Go语言中的sync.WaitGroup模式解决了它。
在最简单的形式中,它看起来像(函数将返回Promise):
function process() {
const locker = {
items: 0,
resolve: null,
lock: function() { this.items++ },
unlock: function() {
if (this.items > 0) this.items--;
if (this.items === 0) {
this.resolve()
this.resolve = null
}
},
};
return new Promise(function(resolve, reject) {
locker.resolve = resolve;
locker.lock();
fastCsv(_config.csvOptions)
.on('end', function() { locker.unlock(); })
.on('data', function(data) {
locker.lock();
const payload = parseRow(data, _config);
kue.create('csv-row', { payload: payload })
.save(function(err) {
if (!err) console.log('Enqueued at ' + job.id);
else console.log('Redis error ' + JSON.stringify(err));
locker.unlock();
});
});
});
}
process().then(function () {
console.log('Now ALL data processed!');
});
在实际应用程序中,您可以将locker
提取到不同的类/模块,添加错误处理等......但原理是相同的 - 等到不仅流是空的,而且还要创建所有非阻塞操作它完成了。