A Beautiful Architecture of Server-Side Alarm

Written by piyushbadkul | Published 2021/12/06
Tech Story Tags: telecommunication | server-side-code | alarm | software-architecture | clean-architecture | telecom-network | inotify | kevent | web-monetization

TLDRThis article shows the hard work put into designing a very small feature when compared to an ocean of telecommunication networks. Telecommunication is one of the most underrated and unapprised things which I believe are the features provided by the telecom giants during the beginning of the packet-switched networks. As of now, multiple service providers have discontinued these features considering the financial aspect and main focus of the telecom operators remains the quality of service in the video, audio or conference calls. With the help of certain libraries, it completes its task of maturing the alarm service for the user.via the TL;DR App

We do not generally appreciate the hard/smart work that goes into creating the things we take for granted around us. Basic things like waste management, electricity transmission, network coverage, water distribution are just taken for granted. This article is one such which shows the efforts put into designing a very small feature when compared to an ocean of telecommunication networks along with the things that really matter to a person.

Telecommunication, no matter how one puts it, is one of the integral parts which constitutes the spine of the nation. For a strong nation, the telecommunication infrastructure needs to be good. The daily livelihood of the entire region goes down, once the networks are down. The same can be said from a strategic point of view. One of the most underrated and unapprised things which I believe are the features provided by the telecom giants during the beginning of the packet-switched networks. Some of these features include Blacklist, Whitelist, Multiple types of forwarding, Call queuing, Personalised ring back tone, alarms, etc.

Nowadays, these features are available in mobile phones through multiple applications available on the play store or app store, and as of now, multiple service providers have discontinued these features considering the financial aspect and main focus of the telecom operators remains the quality of service in the video, audio or conference calls while reducing the latency of the call.

In this article, I would like to bring out the beautiful architecture of the alarm at the server-side of a telecom network. The article can get fairly technical at times, and if you are not from a very technical background or are not aware of this type of coding, you can just simply ignore the coding part and swim through the article.

Invoking the server-side alarm Feature

An alarm feature by a user could be easily invoked using a feature code which includes dialing certain feature code (specific to a telecom service provider) and then appending the time in 24 hours format just after that feature code.

For instance, if someone were to book an alarm for 10:30 AM, he would have to dial *881030 where *88 would be the feature code to invoke the alarm and digits preceding is the time in 24 Hour format.

As soon as the above code would have been dialed through the phone, a request would have been fired from the phone to the server requesting the server to process the code dialed. The server would map the first three-digit of the dialed number with the existing feature codes and the feature code of alarm would be a hit. The hit meant that the user didn’t dial some other subscriber and just requested a service. Then, the server would extract the rest of the digits after the feature code, which is the time (in 24 hours format) at which the alarm should mature.

Once the validity of the time among along with other internal checks was verified, the file would be dumped with the above information into a particular folder created specifically for the alarm services. This file would contain the basic information including the timestamp of time at which the alarm would mature, the address of the person where the alarm would mature, maximum retries of the alarm in case the receiver is unable to pick up, and things like that.

Work done in maturing the alarm at the server for the user.

The server while starting runs multiple threads dedicated to performing specific operations. One of those threads works dedicatedly to spawn the alarms that are requested by the users. With the help of certain libraries, it completes its task of maturing the alarm.

There are 2 libraries which are kevent (kernel event notification mechanism) and inotify (API for monitoring file system events). We can use any one of them to monitor our file system (which is our directory where alarm files would be dumped). We will take inotify in perspective as we move forward in this blog along with some of the kevent too.

First, we need to create an inotify instance that would return a file descriptor and it will register itself and poll the directory frequently.

int inotify_fd = inotify_init();

Then, we need to add that inotify instance associated with a pathname of a particular file or directory, along with some set of events that the kernel should monitor for the file referred to by that pathname to a watch list.

inotify_add_watch(inotify_fd, qdir, IN_CREATE | IN_OPEN |

IN_CLOSE_WRITE | IN_MOVED_TO);

where IN_CREATE, IN_OPEN, IN_CLOSE_WRITE, IN_MOVED_TO are inotify events.

  • IN_CREATE - It means that a file/directory is created in watched directory. In simpler terms, it means that functions like open(), bind(), write(), link(), symlink() are executed.
  • IN_OPEN- It means that a file/directory was opened.
  • IN_CLOSE_WRITE - It means that a file/directory which was opened for writing was closed, just like saving the file after editing it.
  • IN_MOVED_TO - It means that moving a file to a watched directory.

In the server, we make an internal queue structure where the time of the alarms from the files are read and an entry is made into that queue in sorted order of these times. The structure would roughly look like this.

struct directory_entry

{

LIST_QUEUE(directory_entry) list;

time_t alarm_time;

char name[0];

};

Once we have set the watch list, we start by running an infinite loop, something just like this

for ( ; /*ever*/ ; ) { and we would wait for either a) the next timestamp in our queue to occur or b) a change in the monitored directory to happen.

In the loop, for the a) part, we would extract the present time using the time() function and we would attempt to get the alarm time which is the first entry in the queue (as all the times are in sorted order). If the queue is empty, that is no alarm was set, then we would set the alarm time to MAX_VALUE, in which case, we wait forever, otherwise the next would have the time at which the alarm needs to be popped. As soon as the present time exceeds the alarm time, a call was fired up by the server to the person who invoked the alarm feature, his phone would ring continuously for a minute, and if picked up, would have heard an alarm announcement.

In that loop, for the b) part, we would poll the inotify FD every second, and that FD would continuously listen to that monitored directory. Whenever the events occur for monitored files and directories, those events are made available to the application as structured data that can be read from the inotify file descriptor using the read function.

Once the file was added to the directory, after reading, they needed to be added to the queue. The file would be processed according to the inotify event. For an IN_MOVED_TO event, we would simply process the file. The entry would be entered into the queue in the sorted order of the alarm time. Once, it is entered into the queue, the procedure of a) would be followed.

To implement b) part, it could be done through a simple if condition by

if ((res = poll(&poll_fd, 1, 1000)) > 0 &&

(res = read(inotify_fd, &buffer, sizeof(buffer))) >= sizeof(*inotify_event))

where in the poll function, poll_fd would poll on an inotify_fd. the second argument is the number of FD to poll on, and the third argument is timeout which is 1000 millisecond (or 1 second). Parsing of the inotify events in an application can be done by using the read function as shown in the if condition.

If the alarm was matured successfully or it was missed and the time is gone now, we just simply remove the entry from the queue, remove the watch list from that particular file and delete the file from the monitored directory.

Note: the poll function is similar to the select function.

Making the feature fault-tolerant.

To make the server fault-tolerant, that is if someone booked an alarm for a time say X, and the server just gets crashed (which is possible), and restarts again, then that alarm would not mature because the inotify will start monitoring the directory after the server started, and the file was dumped before the server crashed. The subscriber will not get its alarm.

Solution: As soon as the server fully boots up, we process all the files immediately and insert them into the queue. All the upcoming files would be delivered to us through the inotify FD and the files whose time has passed would mature immediately.

Note: The directory which we are monitoring through inotify needs to be closed after being opened to read all the files already present, otherwise, an inotify failure is observed. The same directory while being monitored through kevent may just work fine.

Seeing the differences of the current capabilities that are offered at the hardware level and software level is vast. It simply means that scaling at the hardware side has happened very quickly and very high performing blade servers cost economically, which does not appear to be the case at the software level.

Conclusion

So, in this architecture, one could go by making a thread dedicatedly binding it on a core that would monitor the alarm directory consistently and process it on the go without doing so much as written above. The only downside that appears to be is it will be using 100% of the core all the time which will result in a tremendous amount of electricity bill at the cloud side and wasting of the CPU instructions and IO as it will attempt to read the directory every couple of milliseconds, no matter the alarm feature is invoked or not. Of course, it is the most naive architecture possible, and very little effort would be required to implement it, but it will not be a worthy product.

While the above architecture, no resource is wasted as continuous monitoring will not be done by our application but will be done by the kernel instead. The thread sleeps for a particular amount of time checking the alarm directory only if an inotify event will occur.

That being said, there is always a chance for an improvement in any architecture already implemented, the problem that only arises is that is the new implementation worth it or is it economically feasible as money matters in most cases.

Architecture like this makes me impressed and always wants me to look for a better way to implement my objective. I hope you did understand it and I was able to do justice with this piece. I also hope that it does inspire you too to create something beautiful that the world can really appreciate.


Written by piyushbadkul | Attempting to reuse the wheel instead of reinventing it.
Published by HackerNoon on 2021/12/06