Build Your Own Function Retry Mechanism with Realm
Rate this tutorial
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, 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.
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.
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
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.
The following diagram shows the three use cases contemplated for this scenario.
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).
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.
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.
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).
Sequence Diagram
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.
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.