0
votes

I want to create a cloud function with EXACT 1 INSTANCE ALWAYS...

I dont mind if some users get http 429, 500 or any crazy error code. But I do want to have always max one function online.

Google says that case functions tryes to escaolanate over the max-instances it will throw http 429 to the user... but that is FALSE.

I've doing plent of tests and always it get escalonate up when it reaches some request peak.... So since google ins't able to manage their own created parameters i would like to do by myself.

Is there any way i can get the number of active instances of a specific cloud function? this way i can check if the instance is higher than 1 and drop all requests bymyself

=================UPDATE==================

I've been asked why I want to ensure only single instance... Usually I dont comment archtecture decisions but i will try explain this one.

I don't like the way Firebase Realtime Database handle transactions, is inneficient and might lead to an unnecessary traffic. I've other questions here regarding this topic Android Firebase transaction having a simple counter problem and due this problem I thought is much easier use Cloud Functions as a State aware backeend (although I know it was clearly desingned to not be)

So I create a function that during warm up loads a branch from firebase with few nodes (each node being a counter) into a field...
Everytime a client needs to touch one of the counters it will call my function and, as it is loaded in memory and single threaded, the function will do atomically it and return http 200 (as simple and fast as possible)...
My client was built to the possibility of receiving a http 429 in which case it will wait a random amount of time and retry (untill sucess)

From time to time the function will synchronize with the database just to garantee things are fine. And as the function is now the only entity touching this branch of the database it is garanted to be incorrupt

I've deployed this function a few days ago and according to the dashboard it takes 100ms to reply with the peak of 600ms. so it is absolutelly fine for my standards, BUUUUUUT google is automatically scalonating it to peak of 5 instances... what breaks the integrity of the counters.

2

2 Answers

3
votes

It's not possible to ensure only one instance. That's not how Cloud Functions was designed to work. The documentation states:

Handling traffic spikes

In some cases, such as rapid traffic surges, Cloud Functions may, for a short period of time, create more instances than the specified max instances limit. If your function cannot tolerate this temporary behavior, you may want to factor in a safety margin and set a lower max instances value than your function can tolerate.

It's not clear from your question why you want to limit to only one instance, but Cloud Functions clearly can not guarantee this. It sounds like you need some other solution to your problem. Since you haven't said specifically why you need only one instance, there's not much that can be said as an alternative. Maybe you could use Cloud Tasks to throttle the rate at which the function is being executed by routing all your requests through pubsub topic that gets delivered to a queue and configuring it with a maxConcurrentDispatches of 1, so that it only processes one message at a time.

0
votes

As it was well explained google functions wasn't really built to control or limit instances (the setMaxIntances parameter is just a "we will try, no garantee", what still makes no sence to me). I created this workaround that will work to anyone with similar requirements.

const igDatabase = require('firebase-admin').initializeApp({
//set your firebase config
}).database();

let singleton = false;


function makeid(length) {
   var result           = '';
   var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
   var charactersLength = characters.length;
   for ( var i = 0; i < length; i++ ) {
      result += characters.charAt(Math.floor(Math.random() * charactersLength));
   }
   return result;
}


igDatabase.ref('instances/myFunction').transaction(function(post) {
    if (post === null || post == false){
        singleton = makeid(7);      

        console.log("Finished start up instance: "+singleton);

        return singleton;
    }
    else
        return;

  });


exports.helloworld = (req, res) => {

    if(singleton)
        res.status(200).send("hello world!!");

    else
        res.status(429).send("not valid singleton");


};

I dont like very much this solution but it will do the job.

Problems with this solution:
1- if you redeploy the function without clear the node on which the transaction is watching, you will have a "zero instances scenario"
2 -client must be built to be aware of this situation and retry case http 429
3- IDEALLY after sending http 429 the instance should do something like sleep(random) this would help the client to be connected with another instance after retry. but im not really aware how to do that proper way. Suggestions?