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
- App asks the 3rd party service to send an SMS
- 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 onaskService()
?
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.
- Always be aware whether written code is asynchronous or synchronous.
- Always be aware the variables used access to function level access or global access. Avoid global scope wherever possible.
- 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();
}
}