Interested in speaking at MongoDB World 2022? Click here to become a speaker.
HomeLearnHow-toBuild Your Own Function Retry Mechanism with Realm

Build Your Own Function Retry Mechanism with Realm

Updated: Nov 24, 2021 |

Published: Nov 23, 2021

  • Realm
  • Atlas
  • JavaScript
  • ...

By Josman Pérez Expóstio

Rate this article

#What is Realm?

Wondering what it's 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 Realm 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, Realm 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.

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, Realm 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 Realm 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. Realm 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 four 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 results in an 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 on 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 in 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 here.

This project uses a trigger, newEventsGenerator, to generate a new document every two 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 two. In this way, both states can be simulated.

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

#Conclusion

This tutorial illustrates in a simple way how we can create our own retry mechanism to increase the reliability of our application. Realm allows us to create our application completely serverless, and thanks to the Realm 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.

Rate this article
MongoDB logo
© 2021 MongoDB, Inc.

About

  • Careers
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2021 MongoDB, Inc.