Tips on preventing Realtime database onWrite trigger function callback from iterating through data that has been altered

I am currently developing a 1 vs 1 game matching system using a real-time database. The system works by creating a record in the users table when a user signs in. Once there are two players with a status of placeholder, a cloud function generates a gameInfo for these players and changes their status to waiting. To achieve this, I have implemented a trigger function that observes the status of users/{uid}. When the status is placeholder, the matchmaker function is called to generate a unique gameId for the two players. However, I've encountered an issue where sometimes, due to quick database changes, the trigger function runs twice before the database has fully updated. This results in two unique gameId records being generated instead of one. I'm looking for a solution to prevent this unexpected behavior. Here is a snapshot of the database table: https://i.sstatic.net/oNU59.png

Below is a portion of my cloud function code. The searchWaitingPlayers function checks for two players in the waitingPlayers map and generates a gameId record in the games table.

export const searchWaitingPlayers = functions.database.ref("users/{uid}").onWrite( (change, context) => {
  if (!change.after.exists()) {
    console.log("uid deleted");
    return null;
  } else {
    if (change.after.child("status").val() !== "placeholder") {
      console.log("user's status is not placeholder");
      waitingPlayers.delete(change.after.key);
    } else {
      waitingPlayers.clear();
      admin.database().ref("users").once("value").then(async (users) => {
        users.forEach((user) => {
          if (user.child("status").val() === "placeholder") {
            waitingPlayers.set(user.key, user.child("username").val());
          }
        });
        matchmaker();
      });
    }
    return null;
  }
});

Answer №1

It's a bit unclear when exactly your issue arises, but it appears to be a race condition between two simultaneous updates to the data.

To avoid such conflicts during data updates, consider implementing a transaction process.

Answer №2

If you want to temporarily disable a Cloud Function without deleting it, one workaround is to implement feature flags to control its functionality. You can achieve this by using the following code snippet as a reference.

exports.onDelete = functions.firestore
.document('uploads/{uploadId}')
.onDelete((snap, context) => {
  return ifFeatureEnabled("delete").then(() => {
    console.log("Delete feature is enabled: performing deletion");
    // Perform deletion logic here
  });
});

The `ifFeatureEnabled` function can be used to check if a specific feature flag is enabled in the database:

function ifFeatureEnabled(feature) {
  console.log("Checking if feature '" + feature + "' is enabled");
  return new Promise((resolve, reject) => {
    admin.firestore().collection('config').doc('features')
      .get()
      .then(doc => {
        if (doc.exists && doc.data()[feature]) {
          resolve(doc.data()[feature]);
        } else {
          reject("Feature not found or disabled");
        }
      })
      .catch(error => {
        reject(error);
      });
  });
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Storing multiple items in an array using LocalForage

I have a challenge where I need to add multiple items to an array without overriding them. My initial approach was like this: localForage.getItem("data", (err, results) => { console.log('results', results) // var dataArray ...

What is the best approach to dynamically update CSS using onChange in TypeScript?

I am facing an issue with 2 input fields on my website. I want to create a functionality where if a user enters data into one field, the CSS of the other field changes dynamically. For instance, I would like to change the class "changeAmount" to "display:n ...

Only implement valueChanges on the second step of the form

I am utilizing the mat-stepper with a single form. My stepper has two steps only. I am looking to make an API request for every input value change, but only when the user is on the second step. How can I accomplish this? .ts ngOnInit() { this.formGr ...

Building a table with Next.js

I need assistance in displaying users and their metadata in a table on my website. Here is the code snippet I have: const apiKey = process.env.CLERK_SECRET_KEY; if (!apiKey) { console.error('API_KEY not found in environment variables'); proc ...

Tips for preventing the need to cast a DOM element to any in Typescript

In my Typescript code, I am retrieving the value of a DOM element like this: document.getElementById('MyElementId') as HTMLElement).value I feel unsure about casting it to HTMLElement. Is there a better way to specify the type and retrieve this ...

The efficiency of React Context API's setters is remarkably sluggish

I have a goal to implement a functionality where the background gradient of a page changes depending on whether the child's sublinks are expanded or collapsed. To achieve this, I am using the useContext hook. However, I've noticed that although e ...

What is the process of customizing a Button component from Ant Design using styled components and TypeScript?

I'm trying to customize a Button from Ant Design using TypeScript and styled-components to give it a personalized style. However, I haven't been successful in achieving the desired result. I have experimented with various tests but none of them ...

The error message states that the object literal can only define properties that are known, and in this case, 'tailwindcss' is not recognized in the type 'NuxtConfig'

I'm facing an issue in my nuxt.config.ts file while trying to set up a custom tailwind css path. The error I keep encountering can be viewed here. Can someone guide me on how to properly create the custom tailwind css path in my nuxt.config.ts file? ...

Converting md ElementRef to HtmlElement in Angular 2+: A Step-by-Step Guide

My query is related to retrieving the favorite food input in TypeScript. The input field is defined as: <input mdInput #try placeholder="Favorite food" value="Sushi"> In my TypeScript file, I have accessed this input using: @ViewChild('try ...

Which option is more beneficial for intercepting API data in Angular 6: interfaces or classes?

My API returns JSON data that is not structured the way I need it, so I have to make changes. { "@odata.context":"xxxxxx", "id":"xxxxxxxx", "businessPhones":[ ], "displayName":"name", "givenName":"pseudo", "jobTitle":null, "ma ...

Using *ngFor to populate an array in an ion-list within Ionic 2

Hi there, I'm currently learning Ionic 2 and I recently created an array that I want to loop through in an ion-list. This is my produk.ts import { Component } from '@angular/core'; import { NavController, NavParams } from 'ionic-angul ...

Retrieve both the name and id as values in an angular select dropdown

<select (change)="select($event.target.value)" [ngModel]="gen" class="border border-gray-200 bg-white h-10 pl-6 pr-40 rounded-lg text-sm focus:outline-none appearance-none block cursor-pointer" id="gend ...

Issue: The JSX element 'X' is missing any constructors or call signatures

While working on rendering data using a context provider, I encountered an error message stating "JSX Element type Context does not have any constructor or call signatures." This is the code in my App.tsx file import { Context } from './interfaces/c ...

The index type '{id:number, name:string}' is not compatible for use

I am attempting to generate mock data using a custom model type that I have created. Model export class CategoryModel { /** * Properties */ public id : number; public name : string; /** * Getters */ get Id():number{ return this.id; ...

Is it necessary for me to individually download every x.d.ts file for my application?

Do I need to include the following line for type checking when using fs.readFile in TypeScript? /// <reference path="node.d.ts" /> Is it considered 'best practice' to download and maintain the most recent version of node.d.ts file in my ...

The file isn't located in 'rootDir', even though all the details seem to be accurate

I'm currently troubleshooting an issue with one package in my nx monorepo that is causing the error code "TS6059". Interestingly, all other packages are functioning correctly in previous builds. After reviewing my index.ts files, it appears that all ...

Having trouble locating the name 'angular' in TypeScript error message

I have completed all the necessary settings, such as adding the typescript compiler in webstorm and installing tsd with npm. However, I am still encountering an error stating 'Cannot find name Angular'. tsd.json { "version": "v4", "repo": ...

Is there a method to initiate a 'simple' action when dispatching an action in ngrx?

Here's the scenario I'm facing: When any of the actions listed below are dispatched, I need to update the saving property in the reducer to true. However, currently, I am not handling these actions in the reducer; instead, I handle them in my ef ...

Exploring the concept of rest arrays within a destructured object

Is there a way to declare c as an optional array of any type in this code snippet? const a = ({ b, ...c }: { b: string, c: ? }) => null ...

The border of the Material UI Toggle Button is not appearing

There seems to be an issue with the left border not appearing in the toggle bar below that I created using MuiToggleButton. Any idea what could be causing this? Thank you in advance. view image here view image here Just a note: it works correctly in the ...