Облачная функция Firebase возвращается до завершения функции - PullRequest
0 голосов
/ 07 марта 2019

Я загрузил облачную функцию для выполнения операции обновления в нескольких местах в базе данных.

Когда я загрузил, все работало нормально, но вдруг перестало работать, а в HTTP просто возвращалось {}.

Я снова посмотрел на свой код и обнаружил, что теперь функция возвращает себя {} до завершения функции.

Я не знаю, что вдруг случилось, оно сломало все мое приложение.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const serviceAccount = require('./myapp.json');
admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: 'https://myapp-b2365.firebaseio.com'
});

exports.quarter = functions.https.onRequest((req, res) => {
     userType1 = admin.database().ref('users/Type1').once('value');
     userType2 = admin.database().ref('users/Type2').once('value');
     userType3 = admin.database().ref('users/Type3').once('value');
     userType4 = admin.database().ref('users/Type4').once('value');
    app_con = admin.database().ref('app_con').once('value');
     Promise.all([userType1, userType2, userType3, userType4, app_con]).then(result => {
        console.log(0);
        result[0].forEach(action => {
            action.ref.update({
                'AverageRating': (action.val().Rating  + action.val().AverageRating )/2,
                'Rating': 0
            })
        });
         console.log(1);
        result[1].forEach(action => {
             action.ref.update({
                 'AverageRating': (action.val().Rating  + action.val().AverageRating  )/2,
                 'Rating': 0
             })
         });
        console.log(2);
        result[2].forEach(action => {
            action.ref.update({
                'Rating': 0
            })
        });
         console.log(3);
        result[3].forEach(action => {
            action.ref.update({
                'Rating': 0
            })
        });
        let q = result[4].val().quarter;
        let y = result[4].val().year;
        if (q === 4) {
            q = 1;
            y = y+1;
        } else {
            q = q+1;
        }
        console.log(4);
        result[4].ref.update({
            'quarter': q,
            'year' : y
        })
       return res.send('Done');
    }).catch(error => {
        return res.status(500).send(error);
    })
});

Интересно, что из 4 console.log() я вижу только видение

info: User function triggered, starting execution
info: 0
info: 1
info: 2
info: Execution took 291 ms, user function completed successfully

Я не знаю, что происходит и как это возможно ??

Ответы [ 2 ]

1 голос
/ 07 марта 2019

В вашей функции много асинхронного кода, и она не будет ждать, пока все завершится, прежде чем выйти.

Вы можете решить это, вернув обещание и решив его только после того, как все закончится, примерно так:

exports.quarter = functions.https.onRequest((req, res) => {
  // return a promise so that the function will wait for it to resolve before exiting
  return new Promise((resolve, reject) => {
    userType1 = admin.database().ref('users/Type1').once('value');
    userType2 = admin.database().ref('users/Type2').once('value');
    userType3 = admin.database().ref('users/Type3').once('value');
    userType4 = admin.database().ref('users/Type4').once('value');
    app_con = admin.database().ref('app_con').once('value');
    const promises = [];
    Promise.all([userType1, userType2, userType3, userType4, app_con]).then(result => {
      console.log(0);
      result[0].forEach(action => {
        // add each async operation to a promise so that you can wait for them
        promises.push(action.ref.update({
          'AverageRating': (action.val().Rating + action.val().AverageRating) / 2,
          'Rating': 0
        }));
      });
      console.log(1);
      result[1].forEach(action => {
        promises.push(action.ref.update({
          'AverageRating': (action.val().Rating + action.val().AverageRating) / 2,
          'Rating': 0
        }));
      });
      console.log(2);
      result[2].forEach(action => {
        promises.push(action.ref.update({
          'Rating': 0
        }));
      });
      console.log(3);
      result[3].forEach(action => {
        promises.push(action.ref.update({
          'Rating': 0
        }));
      });
      let q = result[4].val().quarter;
      let y = result[4].val().year;
      if (q === 4) {
        q = 1;
        y = y + 1;
      } else {
        q = q + 1;
      }
      console.log(4);
      promises.push(result[4].ref.update({
        'quarter': q,
        'year': y
      }));
      // wait for all promises created
      Promise.all(promises).then(() => {
        // only after everything completes you can resolve the promise, which causes the function to exit
        resolve(res.send('Done'));
      }).catch((error) => {
        throw error;
      });
    }).catch(error => {
      reject(res.status(500).send(error));
    })
  });
});
0 голосов
/ 07 марта 2019

Рикардо Смания совершенно прав: вы должны использовать обещания (и в вашем случае Promise.all()), чтобы дождаться завершения всей асинхронной работы, прежде чем отправлять ответ.

Должна работать следующая адаптация кода Рикардо:

exports.quarter = functions.https.onRequest((req, res) => {
  // return a promise so that the function will wait for it to resolve before exiting

    userType1 = admin
      .database()
      .ref('users/Type1')
      .once('value');
    userType2 = admin
      .database()
      .ref('users/Type2')
      .once('value');
    userType3 = admin
      .database()
      .ref('users/Type3')
      .once('value');
    userType4 = admin
      .database()
      .ref('users/Type4')
      .once('value');
    app_con = admin
      .database()
      .ref('app_con')
      .once('value');

    Promise.all([userType1, userType2, userType3, userType4, app_con])
      .then(result => {
        const promises = [];
        console.log(0);
        result[0].forEach(action => {
          // add each async operation to a promise so that you can wait for them
          promises.push(
            action.ref.update({
              AverageRating:
                (action.val().Rating + action.val().AverageRating) / 2,
              Rating: 0
            })
          );
        });
        console.log(1);
        result[1].forEach(action => {
          promises.push(
            action.ref.update({
              AverageRating:
                (action.val().Rating + action.val().AverageRating) / 2,
              Rating: 0
            })
          );
        });
        console.log(2);
        result[2].forEach(action => {
          promises.push(
            action.ref.update({
              Rating: 0
            })
          );
        });
        console.log(3);
        result[3].forEach(action => {
          promises.push(
            action.ref.update({
              Rating: 0
            })
          );
        });
        let q = result[4].val().quarter;
        let y = result[4].val().year;
        if (q === 4) {
          q = 1;
          y = y + 1;
        } else {
          q = q + 1;
        }
        console.log(4);
        promises.push(
          result[4].ref.update({
            quarter: q,
            year: y
          })
        );

        return Promise.all(promises);
      })
      .then(result => {
        res.send('Done');
      })
      .catch(error => {
        res.status(500).send(error);
      });

});

Я бы посоветовал вам посмотреть этот официальный видео-сериал для более подробной информации: https://firebase.google.com/docs/functions/video-series/ (в частности, первое видеоиз 3 видео под названием «Изучите обещания JavaScript»).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...