Handling Asynchronous nature of Serverless apps

JavaScript is a single-threaded programming language which means only one thing can happen at a time. That is, the JavaScript engine can only process one statement at a time in a single thread.

The nuances of the Serverless Platform

As a Freshworks app developer if you had worked on any app that uses Serverless components, you are reading the right article. Platform enables the app to observe for a event and call the handler every time certain event occurs. For example, in a sales world, app might want to observe if a contact is created. When a contact is created let’s send an SMS

The server.js would be expected like below,

function askService(..){
 ...
}

function updateTicketProperties(..){
 ...
}

exports = {
   events: [{ event:"onContactCreate", callback: "sendSMS"}]
   sendSMS: function (payload){
    // 1. Talks to 3rd party service to send a SMS
   askService(msg);
   // 2. Update the properties of ticket and notify user
   updateTicketProperties();
}
}

Above code snippet looks almost perfect on if sendSMS(..) has a definition in it’s execution context that only has synchronous JS operations. That means the statements or the function calls inside of this handler wouldn’t take time or neither are returning any promises. In the above case it is clear that SMS sending is handled by a third-party service which might take significant amount of time. Also, updateTicketProperties() would make changes to particular properties of a ticket.

Problem

The platform queues up the all onContactCreate event handlers indirectly and obviously on the nature of JS alongside eventloop. That means whenever a contact is created, sendSMS is queued. The JS execution thread would push askService and updateTicketProperties to the call stack. This is the stack from which

  1. App asks the 3rd party service to send an SMS
  2. Ticket properties are updated.
How the silent problem piles up,

Once askService() and updateTicketProperties() are pushed in the JS call stack, platform assumes your app functionality is achieved and will wait until next time contact is created and call sendSMS .

  • What if, askService() doesn’t actually send SMS because their service is down?
  • What about updateTicketProperties() those are dependant on askService() ?

The result would be unexpected behaviour of the app.

Solution

This is invisible part of JavaScript that even seasoned Freshworks App developers are missing out on. The fix for this problem is a Habit.

  1. Always be aware whether written code is asynchronous or synchronous.
  2. Always be aware the variables used access to function level access or global access. Avoid global scope wherever possible.
  3. Use Promises or async await JS features. This will let app developers to be more certain over async operations. The app will wait until operation is successfully completed or incomplete.

In better way,

function askService(..){
 ...
}

function updateTicketProperties(..){
 ...
}

exports = {
   events: [{ event:"onContactCreate", callback: "sendSMS"}]
   sendSMS: async function (payload){
    // 1. Talks to third party service to send a SMS
   await askService(msg);
   // 2. Update the properties of ticket and notify user
   await updateTicketProperties();
 }
}
2 Likes