PJQuakJag
PJQuakJag

Reputation: 1247

Firebase cloud transaction triggers error

I'm trying to create a distributed counter via a Firestore transaction. I have a collection of Posts each with a subcollection of "count_shards". These each have three documents (1, 2, 3) that contain a "count" field.

When I create a "like" document for a post, I want to choose a random document and increment it by 1. I have the following Typescript code:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();

exports.addShard = functions.firestore
    .document(`likes/{docID}`)
    .onCreate(async (snap, context) => {
        const postID: string = snap.data().postID;
        const randNum: number = (Math.floor(Math.random()*3+1)); 
        const postRef = admin.firestore().doc(`post/${postID}/count_shards/${randNum}`);

        admin.firestore().runTransaction(async transaction => {
            const postShard = (await transaction.get(postRef)).data();
            postShard.count += 1;
            return transaction.update(postRef, postShard);
        });

    });

I get the following error messages:

"ERROR: /Users//firecast/functions/src/index.ts[13, 9]: Promises must be handled appropriately"

"functions@ lint: tslint --project tsconfig.json"

Anyone have any idea what I am doing wrong here?

Upvotes: 0

Views: 136

Answers (2)

Nery Ortez
Nery Ortez

Reputation: 500

The runTransaction method returns a Promise. And as the this blog post says: You have to return that Promise.

And these is important:

...if you want a function to stay alive during async work, you can do this by returning a promise from the function (except for HTTP/S triggers, which require a response sent to the client).

Or in other words: If you don't return that Promise, your function could finish without completing the transaction.

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();

exports.addShard = functions.firestore
    .document(`likes/{docID}`)
    .onCreate(async (snap, context) => {
        const postID: string = snap.data().postID;
        const randNum: number = (Math.floor(Math.random()*3+1)); 
        const postRef = admin.firestore().doc(`post/${postID}/count_shards/${randNum}`);

        return admin.firestore().runTransaction(async transaction => {
            const postShard = (await transaction.get(postRef)).data();
            postShard.count += 1;
            return transaction.update(postRef, postShard);
        });

    });

Upvotes: 0

Doug Stevenson
Doug Stevenson

Reputation: 317808

runTransaction returns a promise. You need to await it.

    await admin.firestore().runTransaction(...);

Upvotes: 1

Related Questions