简而言之:我有一个计划的firebase函数,该函数下载一个文件,将其转换为JSON块,然后将其导入实时数据库。我已经给函数提供了2GB的内存和540秒(最多9分钟)的功能来完成其工作,但它仍会在大约50%的超时时间内结束。一定有泄漏,但这似乎是我的盲点。
详细信息:
我有以下预定功能,每小时运行一次。该函数调用方法updateDatabase
,该方法依次从外部服务器下载一个大小约为35MB的文件(使用方法getNewData
。此文件是一个由空格分隔(不要让您)的文件,其中包含2500行和2500列数据。我需要数据库中的每个数据点,以便稍后快速读取。
起初,我只是将其转换为json并尝试将其导入数据库,因为35MB似乎没什么大不了的。但是,这会使函数每次都耗尽内存。所以我决定将其分成较小的部分。
因此,下载文件时,我首先将其分成几行。然后,我遍历行,将其拆分为列,并在引用/grid/[currentrow]
上的实时数据库上进行设置。这意味着我每次都呼叫2500次。我尝试对每行使用await
,并使用Promise.all()
(当前版本,但有时两者似乎都在某个时候挂起。我在日志中没有发现任何错误,只是540秒过去了。
预定功能:
exports.scheduledDataUpdate = functions
.region("europe-west1")
.runWith({
timeoutSeconds: 540,
memory: '2GB'
})
.pubsub.schedule("0 * * * *")
.onRun(async () => {
try {
await updateDatabase();
console.log('Database updated');
return true;
} catch(error) {
console.error(error);
return false;
}
});
调用方法updateDatabase
:
async function updateDatabase() {
let data;
try {
data = await getNewData().catch(err => console.error(err));
} catch(error) {
console.error(error);
return null;
}
console.log('Data download complete');
const lines = data.split("\n"); // split the data into rows (2500)
lines.forEach((line, r) => {
const cols = line.split(/\s+/); // split the row into columns (2500)
dbUpdates.push(admin.database().ref(`/grid/${r}`).set(cols).then(() => {
if(r > 1 && r % 500 === 0) {
console.log(`updated row ${r}`); // just to get some info in logs whether some rows were processed
}
return true;
}).catch((error) => {
console.error(`Error updating row ${r} -- ${error}`);
}));
return true;
});
return await Promise.all(dbUpdates);
,如果您感到好奇,可以使用方法getNewData
:
const dataUrl = 'https://some.server/somefile'; // I guess you guess this is different in my code (it is)
async function getNewData() {
console.log('Start download of data');
return await new Promise((resolve, reject) => {
https.get(dataUrl, response => {
if (response.statusCode === 200) {
let data = "";
return response
.on("data", chunk => {
data += chunk;
})
.on("end", () => {
resolve(data);
})
.on("error", error => {
reject(error);
console.error(`error while downloading data: ${data}`);
});
} else {
switch (response.statusCode) {
case 301:
case 302:
case 303:
case 307:
console.warning(`Redirected to ${response.headers.location} [${response.statusCode}]`)
return getNewData(response.headers.location);
default:
return reject(new Error(`Could not download new data (error ${response.statusCode})`));
}
}
})
});
}
当我查看firebase提供的配额时(我在Blaze上运行,按需购买,按需付费),这实际上不是一个太大的问题。显然我错过了一些东西或犯了一些愚蠢的错误,但是对于我一生来说,我看不到它。
更新1 带有超时的日志示例(由@FrankvanPuffelen提出)
7:15:03.224 p.m. scheduledDataUpdate Function execution started
7:15:03.546 p.m. scheduledDataUpdate Start download of data
7:15:08.035 p.m. scheduledDataUpdate Data download complete
7:22:28.390 p.m. scheduledDataUpdate updated row 500
7:24:03.244 p.m. scheduledDataUpdate Function execution took 540021 ms, finished with status: 'timeout'
答案 0 :(得分:0)
正如您在对原始问题的评论中看到的那样,Frank van Puffelen提出了这种用例不仅仅是功能环境可以处理的。我做了很多分析,只能得出结论确实如此。因此,我尝试了以下操作:
是的,您的数据大小对性能有重要影响,再次感谢@frankvanpuffelen指出了正确的方向!