Home > front end >  Q: Firebase Extension Limit Child Nodes
Q: Firebase Extension Limit Child Nodes

Time:02-11

I am running a Firebase app with 160k DAU, an online turn based game which uses RTDB to send updates between players. My database load peaks at around 60% at the busiest hour.

A long time problem for me has been how to "clean up" the match node after the game is over. Current structure:

root/games/$gameId

gameId is provided by the host in the matchmaking process. After that both players subscribe to this node and send updates.

What I could do is to have one of the 2 clients delete the node after the game, but that would be another (unreliable) write to increase the database load. My main goal is to keep "dead game nodes" to a minimum and thus the storage cost (Blaze plan). I only recently found out about the extension, but I am curious what my "cost" would be.

Q1: Would every trigger of this extension count as a "write" to my database? Seeing as only 1000 writes per second is allowed for one instance, this would further contribute to this count (it would trigger many times per second).

Q2: In the youtube information video it says it "works best" with auto-generated IDs, but is it needed? https://www.youtube.com/watch?v=i_u_6RknUro

I know that the extension is in fact just a cloud function but I would like to know how it works behind the scenes before I dare to use it :)

Thankful for any help :)

CodePudding user response:

All Firebase Extensions are open-source, so if you want to learn how the Limit Child Nodes extension works, you can check the source code link from its installation page.

The code from there:

export const rtdblimit = functions.handler.database.ref.onCreate(
  async (snapshot): Promise<void> => {
    logs.start();

    try {
      const parentRef = snapshot.ref.parent;
      const parentSnapshot = await parentRef.once("value");

      logs.childCount(parentRef.path, parentSnapshot.numChildren());

      if (parentSnapshot.numChildren() > config.maxCount) {
        let childCount = 0;
        const updates = {};
        parentSnapshot.forEach((child) => {
          if (  childCount <= parentSnapshot.numChildren() - config.maxCount) {
            updates[child.key] = null;
          }
        });

        logs.pathTruncating(parentRef.path, config.maxCount);
        await parentRef.update(updates);
        logs.pathTruncated(parentRef.path, config.maxCount);
      } else {
        logs.pathSkipped(parentRef.path);
      }

      logs.complete();
    } catch (err) {
      logs.error(err);
    }
  }
);

From that it looks like this extension:

  • gets triggered when a new child node is created in the list.
  • then reads the entire parent node to determine how many children there are.
  • then deletes any number of children that are over its maximum with a single write operation.

This matches with my recollection of the code, since I wrote the first version of it. :)

To your questions:

Q1: Would every trigger of this extension count as a "write" to my database?

The triggering of the Cloud Functions happens when you write a child node to the database. It's the write that counts as a write, the trigger itself happens out-of-band. If you read the rest of the code I linked, you'll see that it deletes all child nodes over the maximum as a single write.

Q2: In the youtube information video it says it "works best" with auto-generated IDs, but is it needed?

The nodes are read without an ordering condition (const parentSnapshot = await parentRef.once("value")) and then it deletes nodes from the start of that list. So it assumes the nodes to delete are at the start of the list, when this is ordered by their keys. As long as that applies to your data too, it doesn't matter where the keys come from.

  • Related