Облачная функция Google: удаление документов из хранилища и вставка результата запроса SQL приводит к тайм-ауту - PullRequest
2 голосов
/ 03 мая 2019

У меня есть облачная функция, которая запускается 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);
                });
              }
            }
          });
      });

    });
};

1 Ответ

0 голосов
/ 08 мая 2019

Проблема в моем коде была

if(results !== undefined && Array.isArray(results) && results.length >= 1)

в части «else» этого условия я не вызывал ни функции «разрешить», ни «отклонить» из обещания.

Что объясняет, почему это закончилось тайм-аутом.

(и тот факт, что запрос не возвращал строки, был вызван тем, что я использовал именованный параметр, в то время как mysql поддерживает только '?').

Я не уверен, помогло ли это, но я также изменил способ возврата обещания.

Я переключился на:

 return new Promise((resolve, reject) => {

    deleteCollection(fsCollectionName).then(
      ()=>
      {
        console.log("running query for UL : "+ul_id);
        mysqlPool.query(
          queryStr,
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...