Google Cloud関数:firestoreドキュメントを削除し、SQLクエリの結果を挿入するとタイムアウトになります

トーマス

統計を計算して結果を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]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ