Nicholas Ladefoged
Nicholas Ladefoged

Reputation: 255

Firebase functions

I am building a website like a game. I want to update users' stats (gold, etc.) every 5 minutes for now. To do this I set up a cronjob running every 5 minutes, no problem. However, it seems like firebase functions might "hang" even though on their site, they go for about 5ms.

I just discovered if I "buy" just when the cronjob runs (the function runs) I see that the "gold" does not get updated probably, it gets set right back to when I started buying.

  1. Is my function even acceptable?
  2. Where could the hang be? Is it because I loop through (now 100) fake users?
  3. If so, why would firebase say it takes mostly 5 ms to complete?
  4. Is there any way to make sure, if a user updates just as function is going to secure, that then function update the latest value?
import * as functions from 'firebase-functions';

import * as admin from "firebase-admin";

import {UnitsDTO} from '../../ProjectXFrontend/src/ModelsDTO/Unit/unitsDTO';
import {CurrencyDTO} from '../../ProjectXFrontend/src/ModelsDTO/Currency/CurrencyDTO';

admin.initializeApp();

  export const test = functions.https.onRequest((reques , respon) => {
    admin.database().ref('/LastUpdated').set(
      admin.database.ServerValue.TIMESTAMP
    ).then().catch()
    return respon.send(reques.ip);
  });

  export const GetTime = functions.https.onRequest((request , response) => {
    return response.send({data: new Date()})
  });

  export const CalculateBasics = functions.https.onRequest((request , res) => {
    if (request.ip === '195.201.26.157') {
      CalculateBreeder();
      return res.send('ok');
     } else {
      res.statusCode = 400;
      return res.send(new Error('Bad request'))
    } 

  });

 export const CalculateIncome = functions.https.onRequest((request , res) => {
  if (request.ip === '195.201.26.157') {
    CalculateIncomePrivate();
    return res.send('ok');
  } else {
    res.statusCode = 400;
    return res.send(new Error('Bad request'))
  }
 });




 function CalculateIncomePrivate() {
  admin.database().ref('/users').once('value').then( snap => {
    snap.forEach( child => { 
      const user = child.key // uid
        admin.database().ref('users/' + user).once('value').then(snapUser => {
          const units = new UnitsDTO();
          const currency = new CurrencyDTO();
          if (snapUser.hasChild('Units')) { // in units
            units.worker = snapUser.child('Units').child('worker').val()
          } 
          if (snapUser.hasChild('currency/gold')) { // gold
            currency.goldDto = snapUser.child('currency/gold').val();
          }
          // calculate news
          currency.goldDto.amount += units.worker.amount * units.worker.currencyPerTick;

          // set the Income
          admin.database().ref('users/' + user + '/currency/gold').set(currency.goldDto).then().catch(error => {console.error(error)})
          // update time
          admin.database().ref('/status/LastIncome').set(
            admin.database.ServerValue.TIMESTAMP
          )
          .then(() => {
            // return res.send('ok');

          })
          .catch(error => {
            // res.statusCode = 500;
            // return res.send(error)

          });

      }).catch(error => {
        // res.statusCode = 500;
        // return res.send(error);
      }); 
    })
  }).catch(error => {
    // res.statusCode = 500;
    // return res.send(error);
  })
 }


So, the expected result is of course that the function updates the user's income, which it does, however it seems like it "hangs" and that it doesn't quite update correctly, due to user "buying stuff" when the functions runs.

Upvotes: 0

Views: 61

Answers (1)

cutiko
cutiko

Reputation: 10497

This is an async vs blocking problem.

CalculateIncomePrivate is async, so the code execution will move forward to the next line, returning

So change your function to

function  CalculateIncomePrivate()
    return admin.database...

And then called it like this:

exports.CalculateIncome....
return CalculateIncomePrivate().then(function(){
    resp....
}).catch(function(error){
    resp.status(500).send(error);
});

Make sure that any chained promise is returned.

This should help you with promises https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

And this with Firebase Functions Promises https://www.youtube.com/playlist?list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM

Upvotes: 1

Related Questions