# #javascript #firebase #google-cloud-firestore #google-cloud-functions
Вопрос:
В последнее время я регулярно сталкиваюсь с ошибками в своих облачных функциях firebase. Особенно это функция планировщика, которая запускается каждые 30 минут для обновления данных в магазине firestore.
Мой код выглядит так:
…
exports.updateRiverLevelsData = functions .runWith({ timeoutSeconds: 540, memory: "1GB" }) .pubsub.schedule("every 30 minutes") .onRun(async (context) =gt; { const scotlandResponse = await axios.get( "https://www.riverapp.net/affiliate/api/get_stations?providerId=559ba5cd84821f077403c4b8" ); const irelandResponse = await axios.get( "https://www.riverapp.net/affiliate/api/get_stations?providerId=580e616584821f5ed78e9ee7" ); const walesResponse = await axios.get( "https://www.riverapp.net/affiliate/api/get_stations?providerId=5e4c4c5650ac9c863f897ca3" ); // const englandResponse = await axios.get( // "https://www.riverapp.net/affiliate/api/get_stations?providerId=54aaf0a7e4b01337250b209d" // ); const scotland = await scotlandResponse.data; const ireland = await irelandResponse.data; const wales = await walesResponse.data; // const england = await englandResponse.data; return await Promise.all([ // insertLevels(england, "england"), insertLevels(scotland, "scotland"), insertLevels(ireland, "ireland"), insertLevels(wales, "wales"), ]); }); exports.updateRiverLevelsDataEngland = functions .runWith({ timeoutSeconds: 540, memory: "1GB" }) .pubsub.schedule("every 30 minutes") .onRun(async (context) =gt; { const englandResponse = await axios.get( "https://www.riverapp.net/affiliate/api/get_stations?providerId=54aaf0a7e4b01337250b209d" ); const england = await englandResponse.data; return await insertLevels(england, "england"); }); const insertLevels = async (country: any, label: string) =gt; { const db = admin.firestore(); interface ISomeObject { [key: string]: any; } const legends: ISomeObject = {}; const gaugeLegends: ISomeObject = {}; try { for (let i = 0; i lt; country.length; i ) { let refRiver = country[i].riverName; if (refRiver.includes("/")) { refRiver = refRiver.replace("/", "-"); } if (!legends[refRiver]) { legends[refRiver] = { gauges: [ { gaugename: country[i].gaugeName, lastupdate: new Date(country[i].latestLevelTime).toISOString(), levelseries: [`${country[i].latestLevelValue}`], leveltrend: "", pin: false, rivername: refRiver, temptrend: "", timeseries: [new Date().toISOString()], tempseries: [`${country[i].latestTemperatureValue}`], }, ], }; } else { const temp = legends[refRiver]; const newObj = { gaugename: country[i].gaugeName, lastupdate: new Date(country[i].latestLevelTime).toISOString(), levelseries: [`${country[i].latestLevelValue}`], leveltrend: "", pin: false, rivername: refRiver, temptrend: "", timeseries: [new Date().toISOString()], tempseries: [`${country[i].latestTemperatureValue}`], }; temp.gauges.push(newObj); legends[refRiver] = temp; } } country.map((item: { gaugeName: string | number }) =gt; { if (!gaugeLegends[item.gaugeName]) { gaugeLegends[item.gaugeName] = item; } }); const date = new Date(); // 2009-11-10 const dateKey = date.toLocaleString("default", { month: "long", year: "numeric", }); const refCollection = db.collection("riverStoreLevels").doc(dateKey); const checkData = await refCollection.collection(label).limit(1).get(); if (checkData.size) { const snapshot = await refCollection.collection(label).get(); const data = await snapshot.docs.map((doc) =gt; { return { id: doc.id, ...doc.data(), }; }); data.map((item: any) =gt; { let riverName = item.id; if (riverName.includes("/")) { riverName = riverName.replace("/", "-"); } const gauges = item.gauges; if (legends[riverName]) { for (let i = 0; i lt; gauges.length; i ) { // cari yang sama dengan data yang baru dan lama const oldEachGauge = gauges[i]; const newEachGauge = gaugeLegends[oldEachGauge.gaugename]; if (newEachGauge) { const levelseries = oldEachGauge.levelseries; const tempseries = oldEachGauge.tempseries; const timeseries = oldEachGauge.timeseries; let temptrend = ""; let leveltrend = ""; const latestriverupdate = new Date( newEachGauge.latestLevelTime ).toISOString(); if ( parseFloat(levelseries[levelseries.length - 1]) lt; parseFloat(newEachGauge.latestLevelValue) ) { leveltrend = "raising"; } else if ( parseFloat(levelseries[levelseries.length - 1]) gt; parseFloat(newEachGauge.latestLevelValue) ) { leveltrend = "falling"; } else { leveltrend = "static"; } if ( parseFloat(tempseries[tempseries.length - 1]) lt; parseFloat(newEachGauge.latestTemperatureValue) ) { temptrend = "raising"; } else if ( parseFloat(tempseries[tempseries.length - 1]) gt; parseFloat(newEachGauge.latestTemperatureValue) ) { temptrend = "falling"; } else { temptrend = "static"; } levelseries.push(newEachGauge.latestLevelValue.toString()); tempseries.push(newEachGauge.latestTemperatureValue.toString()); timeseries.push(new Date().toISOString()); oldEachGauge.leveltrend = leveltrend; oldEachGauge.temptrend = temptrend; oldEachGauge.lastupdate = latestriverupdate; } } legends[item.id] = { gauges: item.gauges }; } }); const batchArray: any[] = []; batchArray.push(db.batch()); let operationCounter = 0; let batchIndex = 0; for (const [key, value] of Object.entries(legends)) { let refRiver = key; if (refRiver.includes("/")) { refRiver = refRiver.replace("/", "-"); } const docRef = refCollection.collection(label).doc(refRiver); batchArray[batchIndex].set(docRef, value); operationCounter ; if (operationCounter === 499) { batchArray.push(db.batch()); batchIndex ; operationCounter = 0; } } batchArray.forEach(async (batch) =gt; await batch.commit()); return; } else { console.log("Document Not Exist"); const batchArray: any[] = []; batchArray.push(db.batch()); let operationCounter = 0; let batchIndex = 0; for (const [key, value] of Object.entries(legends)) { let refRiver = key; if (refRiver.includes("/")) { refRiver = refRiver.replace("/", "-"); } const docRef = refCollection.collection(label).doc(refRiver); batchArray[batchIndex].set(docRef, value); operationCounter ; if (operationCounter === 499) { batchArray.push(db.batch()); batchIndex ; operationCounter = 0; } } batchArray.forEach(async (batch) =gt; await batch.commit()); return; } } catch (err) { const e = (err as Error).message; functions.logger.error(e); return; } };
…
функция работает нормально, но иногда не все документы обновляются должным образом, и в журнале всегда появляются ошибки
Error: Process exited with code 16 Error: 4 DEADLINE_EXCEEDED: Deadline exceeded
Я знаю, что первая ошибка означает что-то вроде уже отправленных заголовков, но я не могу понять, в чем проблема с моей функцией. Я также знаю, что для firebase существуют некоторые ограничения на запись, но функция в основном просто обновляет поля массива документов для каждого документа в каждой коллекции.
Структура базы данных: Уровни реки (коллекция) -gt; Дата.сейчас() (документ) -gt;gt; Англия (коллекция) -gt;gt;gt; тест (документ) -gt;gt;gt;gt; тест.данные().датчики (поле, которое будет обновлено)