Nodejs,Cloud Firestore上传任务 – 身份validation错误:错误:套接字挂断

我正在编写一个运行API调用的函数,并通过偏移量从一个巨大的数据库顺序请求JSON。 parsingJSON响应,然后将其中的后续数据上传到我们的Cloud Firestore服务器。

Nodejs(Node 6.11.3)和最新的Firebase Admin SDK

信息按预期parsing,并完美地打印到控制台。 当数据尝试上传到我们的Firestore数据库,但是,控制台被垃圾邮件与错误消息:

身份validation错误:错误:套接字挂断

(节点:846)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝ID:-Number-):错误:从插件获取元数据失败,错误:套接字挂断

偶尔:

身份validation错误:错误:读取ECONNRESET

forEach函数收集下载的JSON中的项目,并在上传到Firestore数据库之前处理数据。 每个JSON都有多达1000个数据项(1000个文档值)通过forEach函数。 我知道这可能是一个问题,如果function重复之前上传设置完成?

我是一个编码新手,并明白,这个function的控制stream是不是最好的。 但是,我无法find有关控制台打印错误的任何信息。 我可以find大量有关套接字挂起的信息,但没有在validation错误部分。

我使用生成的服务帐户JSON作为凭据访问我们的数据库,该数据库使用firebase-adminsdk帐户。 我们对数据库的读/写规则目前是开放的,以允许任何访问(因为我们正在开发没有真正的用户)。

这是我的function:

Firebase初始化和偏移调零

const admin = require('firebase-admin'); var serviceAccount = require("JSON"); admin.initializeApp({ credential: admin.credential.cert(serviceAccount), databaseURL: "URL" }); var db = admin.firestore(); var offset = 0; var failed = false; 

运行function并设置HTTP头

 var runFunction = function runFunction() { var https = require('https'); var options = { host: 'website.com', path: (path including an offset and 1000 row specifier), method: 'GET', json: true, headers: { 'content-type': 'application/json', 'Authorization': 'Basic ' + new Buffer('username' + ':' + 'password').toString('base64') } }; 

运行HTTP请求并重新运行该函数,如果我们尚未达到API响应的结束时间

 if (failed === false) { var req = https.request(options, function (res) { var body = ''; res.setEncoding('utf8'); res.on('data', function (chunk) { body += chunk; }); res.on('end', () => { console.log('Successfully processed HTTPS response'); body = JSON.parse(body); if (body.hasOwnProperty('errors')) { console.log('Body ->' + body) console.log('API Call failed due to server error') console.log('Function failed at ' + offset) req.end(); return } else { if (body.hasOwnProperty('result')) { let result = body.result; if (Object.keys(result).length === 0) { console.log('Function has completed'); failed = true; return; } else { result.forEach(function (item) { var docRef = db.collection('collection').doc(name); console.log(name); var upload = docRef.set({ thing: data, thing2: data, }) }); console.log('Finished offset ' + offset) offset = offset + 1000; failed = false; } if (failed === false) { console.log('Function will repeat with new offset'); console.log('offset = ' + offset); req.end(); runFunction(); } else { console.log('Function will terminate'); } } } }); }); req.on('error', (err) => { console.log('Error -> ' + err) console.log('Function failed at ' + offset) console.log('Repeat from the given offset value or diagnose further') req.end(); }); req.end(); } else { req.end(); } }; runFunction(); 

任何帮助将不胜感激!

UPDATE

我刚刚尝试更改我一次拉的JSON行,随后使用函数 – 从1000下降到100上传。套接字挂起错误不太频繁,所以肯定是由于重载数据库。

理想情况下,如果每个forEach数组迭代在开始之前等待先前的迭代完成,那将是完美的。

更新#2

我已经安装了asynchronous模块,而且我正在使用async.eachSeries函数一次执行一次文档上传。 上传中的所有错误消失 – 但是这个function将花费大量的时间来完成(对于158,000个文档,大概需要9个小时)。 我更新的循环代码是这样的,实现了一个计数器:

 async.eachSeries(result, function (item, callback) { // result.forEach(function (item) { var docRef = db.collection('collection').doc(name); console.log(name); var upload = docRef.set({ thing: data, thing2: data, }, { merge: true }).then(ref => { counter = counter + 1 if (counter == result.length) { console.log('Finished offset ' + offset) offset = offset + 1000; console.log('Function will repeat with new offset') console.log('offset = ' + offset); failed = false; counter = 0 req.end(); runFunction(); } callback() }); }); 

另外,经过一段时间数据库返回这个错误:

(节点:16168)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝标识: – 数字 – ):错误:数据存储操作超时或数据暂时不可用。

现在看起来我的function似乎太长了…而不是不够长。 有没有人有任何build议如何使这个运行更快,没有错误?

作为这个循环的一部分的写请求只是超过了Firestore的配额 – 因此服务器拒绝了大部分的配额。

为了解决这个问题,我一次把我的请求转换成50个左右的项目,Promise确认何时移到下一个块上传。

答案在这里贴出来 – > 在node.js中一次遍历50个数据块的数组,我的工作代码模板如下:

 async function uploadData(dataArray) { try { const chunks = chunkArray(dataArray, 50); for (const [index, chunk] of chunks.entries()) { console.log(` --- Uploading ${index + 1} chunk started ---`); await uploadDataChunk(chunk); console.log(`---Uploading ${index + 1} chunk finished ---`); } } catch (error) { console.log(error) // Catch en error here } } function uploadDataChunk(chunk) { return Promise.all( chunk.map((item) => new Promise((resolve, reject) => { setTimeout( () => { console.log(`Chunk item ${item} uploaded`); resolve(); }, Math.floor(Math.random() * 500) ); })) ); } function chunkArray(array, chunkSize) { return Array.from( { length: Math.ceil(array.length / chunkSize) }, (_, index) => array.slice(index * chunkSize, (index + 1) * chunkSize) ); } 

将数据数组传递给uploadData – 使用uploadData(data); 并将每个项目的上传代码发布到chunk.map函数内的setTimeout块(位于resolve()行之前)的uploadDataChunk中。