Realm Blog
Published in

Realm Blog

Build your own Function Retry Mechanism with Atlas App Services

Realm Serverless

What is Atlas App Services & Realm?

Wondering what is all about? Realm is an object-oriented data model database that will persist data on disk, doesn’t need an ORM, and lets you write less code with full offline capabilities… but Atlas App Services is also a fully-managed back-end service that helps you deliver best-in-class apps across Android, iOS, and Web.

To leverage the full BaaS capabilities, Atlas Functions allow you to define and execute server-side logic for your application. You can call functions from your client applications as well as from other functions and in JSON expressions throughout Realm SDKs.

Functions are written in modern JavaScript (ES6+) and execute in a serverless manner. When you call a function, you can dynamically access components of the current application as well as information about the request to execute the function and the logged-in user that sent the request.

By default, Atlas Functions have no Node.js modules available for import. If you would like to make use of any such modules, you can upload external dependencies to make them available to import into your Atlas Functions.

Motivation

This tutorial is born to show how we can create a retry mechanism for our functions. We have to keep in mind that triggers have their own internal automatic retry mechanism that ensures they are executed. However, functions lack such a mechanism. Atlas functions are executed as HTTP requests, so it is our responsibility to create a mechanism to retry if they fail.

Next, we will show how we can achieve this mechanism in a simple way that could be applied to any project.

Flow diagram

The main basis of this mechanism will be based on states. In this way, we will be able to contemplate 4 different states. Thus, we will have:

  • 0: Not tried. Initial state. When creating a new event that will need to be processed, it will be assigned the initial status 0.
  • 1: Success: Successful status. When an event is successfully executed through our function, it will be assigned this status so that it will not be necessary to retry again.
  • 2: Failed: Failed status. When after executing an event it resolves in error, it will be necessary to retry and therefore it will be assigned a status 2 or failed.
  • 3: Error: It is important to note that we cannot always retry. We must have a limit of retries, when this limit is exhausted, the status will change to error or 3.

The algorithm that will define the passage between states will be the following:

Flow diagram that shows the algorithm behind the state control for events
Flow diagram

System architecture

The system is based on two collections and a trigger. The trigger will be defined as a database trigger that will react each time there is an insert or update in a specific collection. The collection will keep track of the events that need to be processed. Each time this trigger is activated, the event is processed in a function linked to it. The function, when processing the event, may or may not fail and we need to capture the failure to retry.

When the function fails, the event state is updated in the event collection, and as the trigger reacts to inserts and updates, it will call the function again to reprocess the same.

A maximum number of retries will be defined so that, once exhausted, the event will not be reprocessed and will be marked as an error in the error collection.

Sequence diagram

The following diagram shows the three use cases contemplated for this scenario.

Use case 1:

A new document is inserted into the collection of events to be processed. Its initial state is 0 (new) and the number of retries is 0. The trigger is activated and executes the function for this event. The function is executed successfully and the event status is updated to 1 (success).

Use case 2:

A new document is inserted into the collection of events to be processed. Its initial state is 0 (new) and the number of retries is 0. The trigger is activated and executes the function for this event. The function fails and the event status is updated to 2 (failed) and the number of retries is increased to 1.

Use case 3:

A document is updated in the collection of events to be processed. Its initial status is 2 (failed) and the number of retries is less than the maximum allowed. The trigger is activated and executes the function for this event. The function fails, the status remains at 2 (failed), and the counter increases. If the counter for retries is greater than the maximum allowed, the event is sent to the error collection and deleted from the event collection.

Use case 4:

A document is updated in the event collection to be processed. Its initial status is 2 (failed) and the number of retries is less than the maximum allowed. The trigger is activated and executes the function for this event. The function is executed successfully, and the status changes to 1 (success).

Use cases sequence diagram
Sequence Diagram

Project example repository

We can find a simple project that illustrates the above mentioned in this link: https://github.com/josmanperez/realmFunctionRetry

This project uses a trigger: newEventsGenerator to generate a new document every 2 minutes through a cron job in the Events collection. This will simulate the creation of events to be processed.

The trigger eventsProcessor will be in charge of processing the events inserted or updated in the Events collection. To simulate a failure, a function is used that generates a random number and returns whether it is divisible or not by 2. In this way, both states can be simulated.

function getFailOrSuccess() {
// Random number between 1 and 10
const number = Math.floor(Math.random() * 10) + 1;
return ((number % 2) === 0);
}

Conclusions

This tutorial illustrates in a simple way how we can create our own retry mechanism to increase the reliability of our application. Atlas App Services allows us to create our application completely serverless and thanks to the Atlas functions we can define and execute the server-side logic for our application in the cloud.

We can use the functions to handle low latency, short-lived connection logic, and other server-side interactions. Functions are especially useful when we want to work with multiple services, behave dynamically based on the current user, or abstract the implementation details of our client applications.

This retry mechanism we have just created will allow us to handle interaction with other services in a more robust way, letting us know that the action will be reattempted in case of failure.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Josman Pérez Expóstio

If I had to sum up my professional interests in one sentence, I could only say that I am passionate about technology.