【发布时间】:2019-11-07 17:31:19
【问题描述】:
我正在设置一个 Google Cloud Functions (GCF) 函数,该函数经常被触发,以至于有多个实例同时运行。
我从 readStream 中收到错误,流的源文件不存在,但此时在我的程序中我实际上刚刚创建了它。
我已经通过console.log() 确定文件在流开始之前就存在了,因此文件确实 确实存在。我还确保我尝试访问的文件已由先前的流写入完成,并等待,但没有骰子。
编辑:代码现在包含整个脚本。似乎抛出错误的部分是函数 columnDelete()。
var parse = require('fast-csv');
var Storage = require('@google-cloud/storage');
var Transform = require('readable-stream').Transform;
var storage = new Storage();
var bucket = storage.bucket('<BUCKET>');
const DMSs = ['PBS','CDK','One_Eighty','InfoBahn'];
class DeleteColumns extends Transform{
constructor(){
super({objectMode:true})
}
_transform(row, enc, done){
//create an array 2 elements shorter than received
let newRow = new Array(row.length - 2);
//write all data but the first two columns
for(let i = 0; i < newRow.length; i++){
newRow[i] = row[i+2];
}
this.push(newRow.toString() + '\n');
done();
}
}
function rename(file, originalFile, DMS){
return new Promise((resolve, reject) => {
var dealer;
var date;
var header = true;
var parser = parse({delimiter : ",", quote:'\\'});
//for each row of data
var stream = originalFile.createReadStream();
stream.pipe(parser)
.on('data', (row)=>{
//if this is the first line do nothing
if(header){
header = false;
}
//otherwise record the contents of the first two columns and then destroy the stream
else {
dealer = row[0].toString().replace('"', '').replace('"', '');
date = row[1].toString().replace('"', '').replace('"', '');
stream.end();
}
})
.on('finish', function(){
var newName = dealer + ' ' + date + '_' + DMS + 'temp.csv';
//if this was not triggered by the renaming of a file
if(!file.name.includes(dealer)&&!file.name.includes(':')){
console.log('Renamed ' + file.name);
originalFile.copy(newName);
originalFile.copy(newName.replace('temp',''));
}else{
newName = 'Not Renamed';
console.log('Oops, triggered by the rename');
}
resolve(newName);
});
});
}
function columnDelete(fileName){
return new Promise((resolve, reject) =>{
console.log('Deleting Columns...');
console.log(bucket.file(fileName));
var parser = parse({delimiter : ",", quote:'\\'});
var del = new DeleteColumns();
var temp = bucket.file(fileName);
var final = bucket.file(fileName.replace('temp', ''));
//for each row of data
temp.createReadStream()
//parse the csv
.pipe(parser)
//delete first two columns
.pipe(del)
//write to new file
.pipe(final.createWriteStream()
.on('finish', function(){
console.log('Columns Deleted');
temp.delete();
resolve();
})
);
});
}
exports.triggerRename = async(data, context) => {
var DMS = 'Triple';
var file = data;
//if not a temporary file
if(!file.name.includes('temp')){
//create a new File object from the name of the data passed
const originalFile = bucket.file(file.name);
//identify which database this data is from
DMSs.forEach(function(database){
if(file.name.includes(database)){
DMS = database;
}
});
//rename the file
var tempName = await rename(file, originalFile, DMS);
//if it was renamed, delete the extra columns
if (!tempName.includes('Not Renamed')){
await columnDelete(tempName);
}
} else if(file.name.includes('undefined')){
console.log(file.name + ' is invalid. Deleted.');
bucket.file(file.name).delete();
}
else {
console.log( file.name + ' is a temporary file. Did not rename.');
}
};
我期望的输出如下:
Deleting Columns...
Columns Deleted
很好,很简单,让我们知道它什么时候开始和结束。
但是,我得到了这个:
Deleting Columns...
ApiError: No such object: <file> at at Object.parseHttpRespMessage(......)
finished with status: 'crash'
出于显而易见的原因,不希望这样做。我的下一个想法是确保该文件没有被脚本的另一个实例在中途删除,但要做到这一点,我必须检查该文件是否正在被另一个流使用,也就是说,知识,不可能。
有什么想法吗?
【问题讨论】:
-
请编辑问题以显示整个功能,包括在 Cloud Storage 中创建对象,这样我们都可以准确地看到这里发生了什么。
-
已编辑。代码现在包含整个脚本。
-
你说的哪个控制台日志证明文件存在?
-
我在“删除列”日志下方有一个,但在证明文件存在后将其删除。我会加回来的。
-
该日志行不能证明文件存在。它告诉你的只是你已经创建了一个指向该对象的 File 对象,无论它是否存在。正如错误消息所暗示的那样,我会建议您的文件确实不存在。
标签: node.js google-cloud-functions google-cloud-storage node-streams