Cold-Start Workaround in Firebase Cloud Functions
I have been playing firebase cloud functions since the first beta for my side projects. It is really easy to write and can be deployed to production in just a minute. Moreover, it can serve local https api request in development and integrate with Firebase Hosting to do cool stuffs (ex. dynamic meta tag for SPA or even server-side rendering). I insist you give it a shot to try firebase cloud functions and you will wow as I was.
However, the downside of serverless is the time needed (known as “cold start”) to run the instance when the first request hit cloud functions. More explanation about cold start.
Now, let get to the point. A couple months ago, we launched our production app using firestore as database and cloud functions as backend. A lot of customers complained that the app was slow, they had to see loading for so long until they got content (avg. 5–6s). The root cause of this problem was direct to “cold start” in cloud functions because at the beginning we had a few customers using our app, so there was not enough requests to keep cloud functions hot during the day. We made this issue as first priority task because it entirely affected customer’s experience. First I thought that cold start will occur only for the first hit, but it is not. From my investigation, I found that the requests must constantly hit cloud functions on average of 2 minutes, requests after that will receive response faster (a lot faster). And again, if there is no request hit cloud functions for 3-5 minutes, the instance will go to “idle” state and need to pass cold boot again to turn hot.
This is our structure for api path, all of them are https
The cons of this structure is each domain uses different instance. It means cold start time for /users/** and /transactions/** is independent. However, the pros is you can deploy each function separately, so other functions that pass cold boot time will not be affected by deployment.
We researched a lot and found these might help reducing cold start time.
Unfortunately, nothing help until this idea came up.
“If we cannot reducing cold start time, why don’t we just keep it hot all the time”
At first I was hesitated but I had no choices, so I gave it a try because the concept was super easy to implement.
- bundle all domains to one instance which is /api/**
- add simple get https console.log(‘awake’) to /api/awake (or whatever name you want)
- schedule cron to call this api every minute from 7am. to 12pm.
!Hola, it worked. Our customers can feel the difference.
Now let’s take a look at the cost. We schedule every minute from 7am. to 12pm. that are 1020 requests per day. Fortunately, We have already used easy cron with plus plan ($24/yr) because we need to configure header method for another feature, so 1020 requests are still in the package. For firebase, we use blaze plan. From this pricing table, We have to pay around $0.15 per year. Well, That’s not bad. Actually, I think it is the best way at that time because it took an hour to implement and the cost is acceptable. Most importantly, our customers love it.
If you are facing this problem, I recommend you should try this way and let me know if it works in your project or not.