Scaling without Firebase Real-time Database

Abhishek Bharadwaj
5 min readMar 2, 2019
Photo by Samuel Ng on Unsplash

Let me tell you a story about how we build the world’s first AI-based Health chat bot Ria. Ria gives you insights about your food intake and answers all your health-related questions. You can ask her to compare food for you and it suggests you what to eat based on your diet preferences and lifestyle.

Here is a quick video about few things which Ria can do for you.

You can try out Ria here.

It all started with a hackathon idea 1.5 years ago and now we have a team of 15 members including engineers, product managers and content writers dedicated to this product. Being a hackathon project we didn’t have much time to build a real-time chat interface supporting all kind of custom views and interactions. So we reused our already working group chat infra and added chat bot specific functionality on top of that. We were using Firebase real-time database as our middleware. Backend and Frontend both were listening to Firebase and writing and reading from there.

What worked

Implementation was quite fast we were able to push the first version of Ria to the play store within a month from the inception of the idea. People started using it we were getting good feedback. Everything was real-time because of Firebase RTDB we didn’t have to rely on polling based approach or GCM/FCM.

The architecture was simple Client and server both were talking to Firebase so there was no direct interaction. Plus with offline capabilities of the real-time database, we didn’t have to use local DB.

Firebase has this library for loading messages from the real-time database to chat adapter and integrating that was a piece of cake.

Initial architecture of our Chatbot

We used this architecture for about one year but it’s real life and you don’t have happily ever after. So let me tell you what didn’t work.

What didn’t work

There were a few things which didn’t work well for us

  • We were getting some complaints from users as they were not able to use Ria or anything relying on Firebase. Later we found out there was some issue with Firebase auth. This issue was very specific to some ISPs. We had a long email conversation with Firebase support team which ended nowhere.
  • Firebase’s downtime wasn’t helping either and our full premium user onboarding flow was relying on that.
  • One more thing was scalability as new conversations happening on Ria we need our data with us to run all kind of ML and analytics and querying a No-SQL database wasn’t helping either.
  • And the last and very important reason was the future of Firebase real-time database. As rising of its new sibling Cloud Firestore which Google is promoting a lot recently and clearly better than Firebase RTDB in multiple ways. As of now you can see on https://firebase.google.com/ in product listing Cloud Firestore is the first thing and RTDB is last so you know Google’s priority and the main page of RTDB https://firebase.google.com/products/realtime-database/ itself promoting Cloud Firestore so there is a high possibility of Google asking people to migrate to the new kid in the town.

New Architecture

At the beginning of this year, we started working on new architecture which doesn’t rely on Firebase RTDB. So we started making simple rest calls to our backend for every interaction and for proactive messages started relying on FCM. For offline capabilities, we were using SQLite with Room as ORM. To keep a single source of truth we saved everything to our local DB and getting new items using LiveData.

New architecture with Firebase

We were loading everything from the local database itself, so when user sents some message to Ria there were two approaches either we can save it to DB and show in UI without waiting for server sync or wait for server sync and then only show in UI. One way to achieve the second flow was by putting dummy views into recylerview but that makes things complicated when the user is sending lots of messages server is not responding. So keeping the list of unsynced messages and then sending them to Ria engine without breaking conversation flow was a hard problem to solve plus can potentially lead to bugs and messy codebase. We took the first approach as we wanted to make UX smooth and keep the codebase clean.

As every new solution comes with its own problems we faced a few small problems and one was deciding a primary key. We were using Firebase item key as primary for everything from sorting to storing message specific information like rating and other user action related info. As messages were generated from both client and server side so can’t keep the single key. One solution was to keep one autogenerated local id along with id generated by the server and used the local id for everything specific to client and server doesn’t need to know about that. Initially, we thought about keeping auto-increment int but its never a good idea as you can read here https://news.ycombinator.com/item?id=15815327 so we went for auto-generated UUID.

One more issue which we faced was ordering message as with Firebase message id itself was in chronological order and during our testing, we figured out that sometimes server timestamp for the answer was less than question timestamp. So the answer was appearing before the question. The solution was simple just get question timestamp as well with the answer and update the local value with server value.

New architecture went live to play store a few weeks back and everything working fine as of now plus everything is at least twice as fast as Firebase is not there to eavesdrop.

Conclusion

In conclusion, Firebase RTDB works absolutely fine when you are trying to implement some new idea super fast but on the scale when you have different devices and networks to deal with and you want to be in control of your data and run analytics and ML over that then Firebase is not for you.

--

--