Функция Cloud, которая возвращает пакетный коммит, не ждет, пока этот коммит внесет изменения в базу данных, прежде чем он завершится - PullRequest
0 голосов
/ 17 апреля 2020

В облачных функциях я определил функцию, которая делает некоторые обновления, используя пакет, который я фиксирую. Этот коммит является возвращением функции. Эта функция просто вычисляет количество лайков каждого поста (лайки и посты - это две разные коллекции в моей базе данных Firestore). Поскольку весь код является коротким и очень простым для понимания, я покажу его ниже.

Тот факт, что публикация нравится или не нравится (добавление или удаление документа из коллекции лайков) выполняется клиентом приложение. Факт вычисления некоторой статистики (например, количества лайков на пост) ниже серверной части в следующей облачной функции. (потому что, если бы он был на стороне клиента, он был бы взломан, то есть была бы сгенерирована и сохранена плохая статистика + работа со статистикой не имеет отношения к приложению Android напрямую и поэтому должна определенно вычисляться на стороне сервера).

Важно отметить: return batch.commit - это возвращение этой функции облака.

exports.sortPostsByUsersPostsLikes = functions.https.onCall((data, context) => {
    if(!context.auth) {
        throw new functions.https.HttpsError('failed-precondition', 'The function must be called while authenticated.');
    }

    const batch = admin.firestore().batch();
    const posts = admin_firestore.collection('list_of_users_posts');
    const likes = admin_firestore.collection('likes_of_users_posts');
    const map_posts_id_with_number_of_likes = [];
    likes.get().then(function(likes_docs) {
        likes_docs.forEach(like_doc => {
            if(!(like_doc.data().post in map_posts_id_with_number_of_likes)) {
                map_posts_id_with_number_of_likes[like_doc.data().post] = 0;
            }
            map_posts_id_with_number_of_likes[like_doc.data().post] += 1;
        });       
        return posts.get();

    }).then(function(posts_docs) {
        posts_docs.forEach(post_doc => {
            if(post_doc.id in map_posts_id_with_number_of_likes) {
                        batch.update(post_doc.ref, "number_of_likes", map_posts_id_with_number_of_likes[post_doc.id]);
            } else {
                        batch.update(post_doc.ref, "number_of_likes", 0);
            }
        });     
        return batch.commit();

    }).catch(function(error) {
        console.log("UNABLE TO SORT THE POSTS");
        console.log(error);
        throw new functions.https.HttpsError('unknown', 'An error occurred when trying to sort the posts.');
    });

});

В моем приложении Android, когда пользователь, в списке постов лайков:

  1. Сначала я добавляю лайк в коллекцию лайков
  2. Когда лайк успешно добавлен в коллекцию лайков в базе данных, я refre sh список постов
  3. Когда список постов показывается (или обновляется), я вызываю вышеупомянутую облачную функцию, чтобы пересчитать количество лайков постов (скоро, "из показанных сообщений").
  4. Когда число лайков постов успешно пересчитано, я показываю посты (поэтому число лайков каждого показанного поста будет правильным).

Вопрос

Проблема в том, что на шаге 4. количество лайков каждого показанного сообщения НЕ является правильным (иногда это так, иногда нет). Как будто облачная функция не дожидалась окончания пакетной фиксации. Это нормальное поведение? Есть ли способ заставить облачную функцию ждать успешной фиксации пакета?

Код, который я использую в приложении Android, чтобы вызвать вышеупомянутую облачную функцию, а затем, обычно, в случае успеха, выполнить покажи посты (как правило, с большим количеством лайков, но на практике это не так):

        FirebaseFunctions.getInstance()
                .getHttpsCallable("sortPostsByUsersPostsLikes")
                .call()
                .continueWith(new Continuation<HttpsCallableResult, Void>() {
                    @Override
                    public Void then(@NonNull final Task<HttpsCallableResult> task) {
                        if(requireActivity().isDestroyed() || requireActivity().isFinishing()) {
                            return null;
                        }

                        if(!task.isSuccessful()) {
                            Exception e = task.getException();
                            if (e instanceof FirebaseFunctionsException) {
                                FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
                                if(ffe.getCode() == FirebaseFunctionsException.Code.UNKNOWN) {
                                    miscellaneous.showErrorPopIn(requireActivity(), R.string.error_sortPostsByUsersPostsLikes);
                                }
                            }
                            return null;
                        }

                        postsDatabaseModel.getListOfPostsOfUser(the_posts_owner).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {

Возвращение пакетного коммита и добавление then не работает

Я пробовал следующее, но оно не работает:

.then(function(posts_docs) {
        posts_docs.forEach(post_doc => {
            if(post_doc.id in map_posts_id_with_number_of_likes) {
                        batch.update(post_doc.ref, "number_of_likes", map_posts_id_with_number_of_likes[post_doc.id]);
            } else {
                        batch.update(post_doc.ref, "number_of_likes", 0);
            }
        });     
        return batch.commit();

    }).then(function() {
        return true;

    }).catch(function(error) {

1 Ответ

2 голосов
/ 17 апреля 2020

Вы правильно связываете обещания, возвращаемые асинхронными методами, но вы не возвращаете всю эту цепочку. Вы должны сделать следующее:

exports.sortPostsByUsersPostsLikes = functions.https.onCall((data, context) => {
    if(!context.auth) {
        throw new functions.https.HttpsError('failed-precondition', 'The function must be called while authenticated.');
    }

    const batch = admin.firestore().batch();
    const posts = admin_firestore.collection('list_of_users_posts');
    const likes = admin_firestore.collection('likes_of_users_posts');
    const map_posts_id_with_number_of_likes = [];


    // SEE THE ADDITION OF RETURN BELOW
    return likes.get().then(function(likes_docs) {
        likes_docs.forEach(like_doc => {
            if(!(like_doc.data().post in map_posts_id_with_number_of_likes)) {
                map_posts_id_with_number_of_likes[like_doc.data().post] = 0;
            }
            map_posts_id_with_number_of_likes[like_doc.data().post] += 1;
        });       
        return posts.get();

    }).then(function(posts_docs) {
        posts_docs.forEach(post_doc => {
            if(post_doc.id in map_posts_id_with_number_of_likes) {
                        batch.update(post_doc.ref, "number_of_likes", map_posts_id_with_number_of_likes[post_doc.id]);
            } else {
                        batch.update(post_doc.ref, "number_of_likes", 0);
            }
        });     
        return batch.commit();

    }).catch(function(error) {
        console.log("UNABLE TO SORT THE POSTS");
        console.log(error);
        throw new functions.https.HttpsError('unknown', 'An error occurred when trying to sort the posts.');
    });
});

Я бы посоветовал вам посмотреть 3 видео о "JavaScript Promises" из серии видеороликов Firebase (https://firebase.google.com/docs/functions/video-series/), которые Подчеркните, как важно вернуть Обещание. Без этого облачная функция может завершиться в любое время до завершения всех асинхронных операций.


ОБНОВЛЕНИЕ СЛЕДУЮЩИХ ВАШИХ КОММЕНТАРИЙ

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

exports.sortPostsByUsersPostsLikes = functions.https.onCall((data, context) => {
    if(!context.auth) {
        throw new functions.https.HttpsError('failed-precondition', 'The function must be called while authenticated.');
    }

    //...

    return likes.get().then(function(likes_docs) {
        //...      
        return posts.get();

    }).then(function(posts_docs) {
        //...          
        return batch.commit();

    }).then(function() {
        console.log("SUCCESS")   
        return null;
    })
     .catch(function(error) {
        //...
    });

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