У меня есть облачная функция, которая запускается crontab для вычисления статистики и вставки результатов в Firestore.
Моя облачная функция удаляет предыдущую статистику в firestore, а затем выполняет запрос CloudSQL (MySQL) и пакетно вставляет результат в firestore.
MySQL Query отвечает почти мгновенно.
Выполнение занимает максимум 9 минут, что невозможно.
Я думаю, что у меня может быть проблема с цепочкой обещаний. MySQL lib изначально не поддерживает обещание, и я новичок в этом.
Полный код здесь:
https://github.com/dev-mansonthomas/RedCrossQuestCloudFunctions/blob/master/RCQ/ULQueteurStatsPerYear/index.js
'use strict';
const mysql = require('mysql');
const {Firestore} = require('@google-cloud/firestore');
const firestore = new Firestore ({projectId:process.env.TARGET_PROJECT_ID});
const settings = {timestampsInSnapshots: true};
firestore.settings(settings);
const fsCollectionName = 'ul_queteur_stats_per_year';
const connectionName = process.env.INSTANCE_CONNECTION_NAME || null;
const dbUser = process.env.SQL_USER || null;
const dbPassword = process.env.SQL_PASSWORD || null;
const dbName = process.env.SQL_DB_NAME || null;
const mysqlConfig = {
connectionLimit : 1,
user : dbUser,
password : dbPassword,
database : dbName,
};
if (process.env.NODE_ENV === 'production') {
mysqlConfig.socketPath = `/cloudsql/${connectionName}`;
}
// Connection pools reuse connections between invocations,
// and handle dropped or expired connections automatically.
let mysqlPool;
const queryStr = ['the big SQL query'].join('\n');
exports.ULQueteurStatsPerYear = (event, context) => {
const pubsubMessage = event.data;
const parsedObject = JSON.parse(Buffer.from(pubsubMessage, 'base64').toString());
const ul_id = parsedObject.id;
// Initialize the pool lazily, in case SQL access isnt needed for this
// GCF instance. Doing so minimizes the number of active SQL connections,
// which helps keep your GCF instances under SQL connection limits.
if (!mysqlPool)
{
mysqlPool = mysql.createPool(mysqlConfig);
}
//delete current stats of the UL
let deleteCollection = function(path)
{
console.log("removing documents on collection '"+path+"' for ul_id="+ul_id);
// Get a new write batch
let batch = firestore.batch();
return firestore.collection(path).listDocuments().then(val => {
val.map((val) => {
if(val.ul_id === ul_id)
{
batch.delete(val)
}
});
return batch.commit();
});
};
//then inserting new one
return deleteCollection("ULQueteurStatsPerYear").then(
()=>
{
return new Promise((resolve, reject) => {
mysqlPool.query(
queryStr,
[ul_id],
(err, results) => {
if (err)
{
console.error(err);
reject(err);
}
else
{
if(results !== undefined && Array.isArray(results) && results.length >= 1)
{
const batch = firestore.batch();
const collection = firestore.collection(fsCollectionName);
let i = 0;
results.forEach(
(row) =>
{
//console.log("ULQueteurStatsPerYear : inserting row for UL "+ul_id+" "+JSON.stringify(row));
const docRef = collection.doc();
//otherwise we get this error from firestore : Firestore doesn’t support JavaScript objects with custom prototypes (i.e. objects that were created via the “new” operator)
batch.set(docRef, JSON.parse(JSON.stringify(row)));
});
return batch.commit().then(() => {
let logMessage = "ULQueteurStatsPerYear for UL='"+parsedObject.name+"'("+ul_id+") : "+i+" rows inserted";
console.log(logMessage);
resolve(logMessage);
});
}
}
});
});
});
};