Search code examples
databasefirebasefirebase-realtime-databasegoogle-cloud-functions

Is there a way to avoid double invocation using Firebase trigger where the trigger updates its own node?


I have a turn based game where I want to validate and process data sent by each player, and update the state afterwards using firebase triggers. Currently using RTDB. To clarify, the node looks like this:

  • gameId
    • state
      • userTurn: String?
      • stateVariables
        • var1
        • var2 etc

So, I currently have a trigger on gameId/state. If userTurn is not null, pass userTurn along with current stateVariables to a function that creates a new game state, then update the state variables, removing the userTurn.

When the trigger removes the userTurn (and updating stateVariables), the trigger will fire again. But since userTurn is null, I will return null and then we wait for the next player's turn.

Why am I doing it like this? Because speed is important, I want to process the data as fast as possible. There is a timer, and turns have to go as fast as possible for the sake of user experience.

The problem is obvious: For every move, there will be 2 invocation and 2 reads by the trigger, which will increase the cost for me.

I have thought about simply putting the trigger on gameId/state/userTurn and read gameId/state/stateVariables -> update the state again. BUT that will increase the time between turns and increase the perceived latency for all players. The good part of my current solutions is that the trigger has instant access to the data in stateVariables when triggered.

So my question is: Is there a way to avoid double invocations? Or a better way?

Thankful for any help and ideas!


Solution

  • There is no way to prevent this double invocation without changing the data model. You'll have to detect and abort the function the second time around.

    If you're willing to change the data model, the common solution is to have two separate queues (here likely based on the userTurn value) and move the task from one queue to the other.