2017-10-07 84 views
5

API çağrılarını çalıştıran ve JSON'u büyük bir veritabanından sekanslar aracılığıyla sırayla gönderen bir işlevi kodluyorum. JSON cevabı ayrıştırıldı ve ardından gelen veriler Cloud Firestore sunucumuza yüklendi.Nodejs, Cloud Firestore Yükleme Görevleri - Auth hatası: Hata: yuva asmak

Nodejs (Düğüm 6.11.3) & Son Firebase Yönetici SDK

bilgiler beklendiği gibi çözümlenir ve baskılar mükemmel konsola edilir.

Auth error:Error: socket hang up

(node:846) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: -Number-): Error: Getting metadata from plugin failed with error: socket hang up

ve bazen:

Auth error:Error: read ECONNRESET

forEach işlevi indirilen JSON ve süreçlerin öğeleri toplar veri Ancak bizim Firestore veritabanına yüklemek çalıştığında, konsol hata mesajı spammed Firestore veritabanına yüklemeden önce verileri. Her JSON, forEach işlevinden geçmek için 1000 öğeye kadar (1000 belge) veri içerir. Yükleme kümesinin bitmeden işlevi tekrarlarsa, bunun bir sorun olabileceğini anlıyorum.

Ben bir kodlama uzmanıyım ve bu işlevin kontrol akışının en iyi olmadığını anlıyorum. Ancak konsolun yazdırdığı hatayla ilgili hiçbir bilgi bulamıyorum. Yuva asmakları hakkında birçok bilgi bulabilirim, ancak hiçbiri Yetkilendirme hatası bölümünde yok.

Firebase-adminsdk hesabını kullanan veritabanımıza erişmek için oluşturulmuş bir hizmet hesabı JSON kimlik bilgisi olarak kullanıyorum. Veritabanımız için okuma/yazma kurallarımız, herhangi bir erişime izin vermek için şu anda açıktır (gerçek kullanıcılar olmadan geliştirdiğimiz gibi). & sıfır ing

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; 

Koşu fonksiyonu & ayarı HTTP Başlıkları

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') 
     } 
    }; 

Koşu ofset

Firebase hazırlama: Burada

benim işlevi var HTTP İstek & Yeniden çalışan işlevi biz Herhangi bir yardım büyük takdir

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(); 

API gelen yanıtın sonuna ulaşmış değil eğer! soket 100'e kadar 1000 den hatalar daha az olan asmak -

GÜNCELLEME

Sadece bir defada çekin ve daha sonra işlevini kullanarak bir seferde yüklemek JSON satırlarını değişen denedim sık sık bu yüzden veritabanının aşırı yüklenmesi nedeniyle.

İdeal olarak, her forEach dizisi yinelemesi, başlamadan önce önceki iterasyonun tamamlanmasını beklediğinde mükemmel olur.

ben zaman uyumsuz modülü yükledim ve şu anda async.eachSeries seferinde bir belge yükleme gerçekleştirmek için işlev kullanıyorum 2

GÜNCELLEME #. Yükleme sırasında meydana gelen tüm hatalar ortadan kalkar - ancak işlev bitmek için çok fazla zaman alır (158.000 doküman için yaklaşık 9 saat). Benim güncellenmiş döngü kodu uygulanan bir sayaç ile, şudur: Benim işlevi çok uzun sürüyor şimdi sanki

(node:16168) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: -Number-): Error: The datastore operation timed out, or the data was temporarily unavailable.

Öyle görünüyor:

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() 
    }); 
}); 

Ayrıca bir süre sonra veritabanı bu hatayı döndürür ... yeterince uzun değil. Bu koşulu, belirtilen hatalar olmadan daha hızlı hale getirme konusunda herhangi bir tavsiyede bulunur mu?

cevap

2

Bu döngünün bir parçası olarak yazma istekleri yalnızca Firestore'un kotasını aştı - dolayısıyla sunucu çoğunluğunu reddediyordu.

Bu sorunu gidermek için, istekleri bir kerede 50 veya daha fazla öğeden oluşan parçalara yüklemeye dönüştürdüm, sözler bir sonraki yığın yüklemeye ne zaman taşınacağını onaylıyor. >Iterate through an array in blocks of 50 items at a time in node.js ve benim çalışma kodu için şablon olarak altındadır -

cevap burada yayınlanmıştır:

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 üzerine veri dizi iletin - uploadData (veri) kullanılarak; ve her bir öğe için yükleme kodunuzu setTimeout bloğu içinde (resol() satırında) chunk.map işlevi içinde uploadDataChunk içine gönderin.

0

Her biri arasında 50 milisaniyede beklemeyle chaining the promises in the loop numaralı belgede var.

function Wait() { 
    return new Promise(r => setTimeout(r, 50)) 
} 

function writeDataToFirestoreParentPhones(data) { 
    let chain = Promise.resolve(); 
    for (let i = 0; i < data.length; ++i) { 
     var docRef = db.collection('parent_phones').doc(data[i].kp_ID_for_Realm); 
     chain = chain.then(()=> { 
      var setAda = docRef.set({ 
       parent_id: data[i].kf_ParentID, 
       contact_number: data[i].contact_number, 
       contact_type: data[i].contact_type 
      }).then(ref => { 
       console.log(i + ' - Added parent_phones with ID: ', data[i].kp_ID_for_Realm); 
      }).catch(function(error) { 
       console.error("Error writing document: ", error); 
      }); 
     }) 
     .then(Wait) 
    } 
} 
+0

Her firestore docSet tarafından döndürülen bireysel sözleri kullanmak daha iyi olabilir. İçindeki sözleri çözüyorum, böylece kodum, önceki tüm yığınlar yüklendiğinde yalnızca bir sonraki yükleme yığınına geçiyor. İterasyonlar arasındaki bekleme beklemelerini kaldırır. – Hendies