Architecting merchant powered Promotions in GO-FOOD

How we went about building an in-house service to automate promotions with GO-FOOD

Architecting merchant powered Promotions in GO-FOOD

By Aayush Sharda

GO-FOOD, our food delivery product is one of the largest food delivery services in the world. We operate at a massive scale and do a good portion of our overall monthly orders of a 100+ million via GO-FOOD.

The Content Management Service in GO-FOOD handles a throughput of about 200k rpm serving multiple user requests. Keeping the service performant while catering to such high loads has always been an exciting challenge for us. You can consider this service to be a simple read service for all kinds of food content discovery requests.

Discounts and promotions in GO-FOOD have existed since its inception. But our content team found creating and managing these discounts tedious. Moreover, we did not make these discounts discoverable for our consumers.

The old school way of doing this:

  • The Content team used to update prices of individual menu items that were to be put on a discount by substituting original prices with discounted prices.
  • Customers saw the discounted price as the original price of the items. Now, there was no visibility of promotions being available even when they were discounted.
  • When the discount was deactivated, the prices of the menu items had to be changed back to the original price manually.
To solve this problem we developed GO-FOOD’s Promotion Engine — GODFATHER. (And yes, it makes an offer you can’t refuse.)

The job of Godfather is to create and update promotions for any item in a merchant’s menu automatically as and when the merchant pleases. It also powers the content API with promotions information, so it’s visible to customers in realtime. With this service in place, the content management team can simply apply promotions on one or more menu items of a particular brand at the same time or merchants can manage their own restaurant specific promotions via GO-RESTO.

Taking a sneak peek into this solution introduced us to another interesting problem: latency.

source: https://wefe.in/tag/latency

We could not afford high latency when a customer browses through GO-FOOD, given the kind of load it handles. So introducing a network call from content service to Godfather for promo information was out of the question. Also, we could not just introduce promo handling at content service because these two things had a clear separation of concerns. And cluttering one service with multiple jobs has served us poorly in the past. We wanted the content service to be agnostic about these promotions, but worry only about consumer discounts.

The use cases at hand were:

  • Promotions may not be applied as soon as they are created and every promotion will have an activation and deactivation time during which the it should be active
  • At a point in time there can only be one promotion on a menu item
  • Promotions will be active for a period which is in multiple of hours

Architecture

  1. Promotions are created by the content team or merchants themselves in Godfather. Their presence should be conveyed to the content service at the time of activation, and at the time of deactivation, their removal should be propagated.
  2. An async worker is scheduled to push the (activation or deactivation) event information to Kafka just before the event is planned to go live.
  3. Multiple consumers can consume this message from Kafka including the one which has to make content service aware of the discount. This consumer reads the promotion info which is to be applicable on multiple menu items and makes an http request to content service with this information in a pre-agreed contract.
  4. At the content service end, we created another field in the menu item model, named as promotion, which would simply contain the promo info as a JSON blob. With this approach, we could consume the message passed by a Lambda worker as it is and just populate the promotion field of the menu items, or remove the promotion details if a deactivation message is sent.

This makes the content service unaware of a running promotion, as it simply returns the stored promotion to our suite of consumer apps. With this approach, we were able to serve this information without making any additional network calls at runtime.

We’re striving hard to make discounts accessible to our consumers. But with this engine in place, merchants themselves can plan to give discounts on items and boost sales; and consumers get the direct benefit of such discounts.

Coming up next on GO-FOOD: how to make improve adoption of promotions and provide personalized recommendations for users to obtain maximum conversions. Stay tuned 🖖

Found this interesting? Any suggestions? Please leave a comment below. Grab this chance to work with GO-JEK. We’re expanding at insane rates and want the best developers to crack complex problems. And you get to build cool products and give them kickass names. 😉 Head to gojek.jobs for more.