How we developed the notifications service
By: Dmitriy Syrovatskiy
Tags: Software Development, Program Architecture

In this article, I will tell how we developed the notifications system, which was recently launched in VMmanager (our server virtualization management platform). I will focus on system architecture and implementation details: which technology stack was used, which decisions were made and why, and what happened in the end. I will also tell you how dynamic data updates are arranged in our single-page application.

Task

To implement a user notification service for various event types, e.g. an unfinished task, resource overuse or low account balance.

Key requirements to the service:

Easy integration with existing company products

Ability to work with different sources of events

Sending events to different channels (email, interface and messengers)

As a result, we should get an easy to use framework: it should be sufficient to connect it to your project and specify the business logic of the necessary processing modules in any convenient programming language.

Here’s what we have done

To reduce the number of reader’s questions about why certain decisions were made, let us review the architecture of existing ISPsystem products. Namely, we are interested in the part that is responsible for sharing updates between Backend and Frontend.

Diagram 1. Updates exchange between Backend and Frontend

All our products are single-page applications, where a service called Notifier is responsible for dynamic data update.

Here is its operating logic (diagram 1):

The user opens the website page.

Frontend (FE) via websocket (WS) subscribes to events of certain entities from Notifier. In our case, it subscribes to all virtual machine (VM) events.

The user creates a VM.

Backend (BE) starts the VM creation task.

BE compiles a notification for the Notifier about creation of the virtual machine.

Frontend learns about the new VM through WS.

The user sees the new VM in the list of virtual machines, which has the “Installation in progress” status.

Interestingly, Frontend not only learns about the event, but also receives full information about the entity.

We have simply removed the extra link from the FE chain:

subscribe → get the update → r̶e̶q̶u̶e̶s̶t̶ ̶t̶o̶ ̶B̶E̶ →display the object

At the time of subscription, Frontend provides to Notifier the endpoint, which needs to be requested when the update is received. This way, FE gets the complete element with the update. As the result, we are saving time on the query.

Result

Diagram 2. Final arrangement of the notifications service

The result is provided shown in diagram 2. Let us review it.

Alert configurator

This is the input point, where notification settings will be entered. It is a microservice, whose functions include:

To accept the settings consisting of a number of mandatory fields and additional information in free format.

Release the list of settings by the final alert name.

And process two or three endpoints, which meet the CRUD paradigm.

{

"name":"string",

"metric":{},

"channel":{},

"enabled":bool

}

name — final alert name for filtration.

— final alert name for filtration. metric — the object, which is included into the final alert unchanged. It contains data in random format, which are different from one alert to another.

— the object, which is included into the final alert unchanged. It contains data in random format, which are different from one alert to another. channel — the object with channels to which notifications need to be sent. Each channel contains recipients, e.g. chatID for telegram or list of IDs for email notifications.

— the object with channels to which notifications need to be sent. Each channel contains recipients, e.g. chatID for telegram or list of IDs for email notifications. enabled — the field controlling whether the setting is enabled.

Final alert wrapper

This is an executable file that starts the final alert, reads its output stream (stdout) and writes to the input stream (stdin). It takes over all the work with the configs and entities required for operation of the alert, as well as sending messages to the notice-center.

Let us take a look at the basic principles of the wrapper using the example of the sequence diagram.