統計を計算して結果をFirestoreに挿入するために、crontabによってトリガーされるクラウド関数があります。
私のクラウド関数は、firestore内の以前の統計を削除してから、CloudSQLクエリ(MySQL)を実行し、結果をfirestoreにバッチ挿入します。
MySQLクエリはほぼ瞬時に応答します。
実行には最大9分かかりますが、これは不可能です。
約束の連鎖に問題があるのではないかと思います。MySQL libはネイティブでpromiseをサポートしておらず、私はこれに不慣れです。
完全なコードはここにあります: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);
});
}
}
});
});
});
};
私のコードの問題は
if(results !== undefined && Array.isArray(results) && results.length >= 1)
この条件の「else」部分では、promiseから「resolve」関数または「reject」関数を呼び出していませんでした。
これが、タイムアウトで終了した理由を説明しています。
(そして、クエリが行を返さなかったという事実は、mysqlが '?'のみをサポートしているのに名前付きパラメーターを使用したためです)。
それが役に立ったかどうかはわかりませんが、約束を返す方法も変更しました。
私はに切り替えました:
return new Promise((resolve, reject) => {
deleteCollection(fsCollectionName).then(
()=>
{
console.log("running query for UL : "+ul_id);
mysqlPool.query(
queryStr,
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加