<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Meet Gandhi</title>
    <description>The latest articles on DEV Community by Meet Gandhi (@geniusmind9999).</description>
    <link>https://dev.to/geniusmind9999</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3581063%2Fff016f6b-facf-4a8d-be41-0d366d0ff97c.jpg</url>
      <title>DEV Community: Meet Gandhi</title>
      <link>https://dev.to/geniusmind9999</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geniusmind9999"/>
    <language>en</language>
    <item>
      <title>I wrote bi-directional tcp congestion control... and survived!</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Sun, 04 Oct 2026 06:54:46 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/i-wrote-bi-directional-tcp-congestion-control-and-survived-5937</link>
      <guid>https://dev.to/geniusmind9999/i-wrote-bi-directional-tcp-congestion-control-and-survived-5937</guid>
      <description>&lt;p&gt;I'm back again after a loong break but this time I have done a lot of things apart from what I said in the last blog (obviously 🙃).&lt;/p&gt;

&lt;p&gt;This time I'll be discussing on how I wrote the logic for using TCP in an event loop even though it is a stream oriented protocol. So my idea was simple but it took a long time to come, and this time it was purely my idea — I was sleeping and suddenly I woke up in the middle of the night and my brain was like "Hey, what if we write the size of the packet in it?" and I was like "BROO, right now?"&lt;/p&gt;

&lt;p&gt;That did not happen exactly 😂. I simply slept without acknowledging the idea and the next day I woke up and again thought for an hour and then I remembered about this idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what was the idea?
&lt;/h2&gt;

&lt;p&gt;The idea is that say I have my TCP packet wherein I have some fixed size data (we'll do variable size later). Now its really easy in UDP just because UDP is packet oriented which means it preserves packet boundaries meanwhile TCP does not (that's one of the reasons why it is so good!)&lt;/p&gt;

&lt;p&gt;So how do we get this amazing UDP property from TCP? The idea is simple, write down the packet size on the packet itself.&lt;/p&gt;

&lt;p&gt;Say you have the packet struct defined as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;myPacket&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;packetSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;someData2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ...some more data&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now here, we if do &lt;code&gt;sizeof(struct myPacket)&lt;/code&gt; we will get the answer as &lt;code&gt;16&lt;/code&gt; (yes it's not &lt;code&gt;13&lt;/code&gt; as I expected earlier because of compiler adding some padding to make &lt;code&gt;13&lt;/code&gt; a multiple of &lt;code&gt;4&lt;/code&gt; which makes it easier for the CPU to fetch the pages from memory).&lt;/p&gt;

&lt;p&gt;And the value of the &lt;code&gt;packetSize&lt;/code&gt; member is &lt;code&gt;16&lt;/code&gt;. So now picture this, you're doing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;???&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you don't know the value you should put into your buffer since you don't know what packet is coming. But now if every packet sent by the other side (which is also your own code, atleast in my case it is 😂) has this size defined as the first member of the struct you could simply do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And once you get that, read the value of buf and figure out the packet size like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;myPacket&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;myPacket&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;packetSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I've written more code than needed because I wanted to make it look more "complete" 😅&lt;/p&gt;

&lt;p&gt;What's happening here is that first we read an int from the stream. now this int contains the size of the packet (ofc, you'd need ntohs here, but I figured that'd make this more hard to read). And then you simply read the rest of the packet in a struct. Now you don't have to read the remaining data at the start of the struct hence the &lt;code&gt;mp + size&lt;/code&gt; instead of &lt;code&gt;mp&lt;/code&gt; alone. Now I know it would be much better and safer to use &lt;code&gt;offsetof&lt;/code&gt; but for an example this works great.&lt;/p&gt;

&lt;p&gt;Anyways this was when everything is great and life is simple. But sadly that ain't true (I wish it was 🫠). So now what if the data hasn't arrived yet? I mean the member &lt;code&gt;someData&lt;/code&gt; has arrived but &lt;code&gt;someData2&lt;/code&gt; is still travelling on the network. And when you demand for the entire data &lt;code&gt;read&lt;/code&gt; does something clever, it simply blocks you. And that is not a good thing when you're in an event loop since the kernel does not know that you're doing multi threading without telling it and one such blocking call is quite deadly since the entire process goes into the blocked state until the packet is not complete.&lt;/p&gt;

&lt;p&gt;Think about that for a second, until the entire packet arrives, no heartbeats, no voting, nothing the node can do. For the node it simply underwent time travel 😵. So we do not want to handle time glitches in a system that is already handling a thousand other things. So the kernel gives us a solution, make the &lt;code&gt;read&lt;/code&gt; function non blocking (hurray!). I already wrote this in the previous blog but I'll anyways repeat it. So once the &lt;code&gt;read&lt;/code&gt; function is non-blocking we have the control to what we want to do except sleeping.&lt;/p&gt;

&lt;p&gt;So here's the thing, the Assigner I have in mind acts as a congestion control for the Gateway and the Worker and hence it looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fut6nav767ggv9nvstw2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fut6nav767ggv9nvstw2b.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So if suppose the diagram was simpler with the &lt;code&gt;Gateway Data (IN)&lt;/code&gt; going to &lt;code&gt;Worker Data (OUT)&lt;/code&gt;. Now in this case if the Gateway sends more data than what I can store (say, my TCP buffer is full as well as the buffer I allocate using malloc) but the worker is slow and hence the buffer in the workers side sending data eventually fills up and no more data can go in. To visualize it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdm0geveplsel54eqzbtd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdm0geveplsel54eqzbtd.gif" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So here as you see the data flows in chunks, green indicates the data is there but the buffer is not yet full. Then red indicates the buffer is full and there is not space. So now to implement congestion control I need to stop the gateway when the worker's internal buffer fills up. And since we're using epoll how do we do this?&lt;/p&gt;

&lt;p&gt;First thing we do is add the events &lt;code&gt;EPOLLIN&lt;/code&gt; and &lt;code&gt;EPOLLOUT&lt;/code&gt; to both the sockets along with &lt;code&gt;EPOLLET&lt;/code&gt;. Now you'll find the descriptions in the man pages of epoll (7) but its better if I maintain the flow here. So &lt;code&gt;EPOLLET&lt;/code&gt; simply means that if the buffer was full and now some data is removed tell me and if the buffer was empty and some data has come in tell me. It won't tell you unless the extremes change, i.e., if new data arrives and there was data previously which you forgot to read, you're basically dead meat 😂, epoll in &lt;code&gt;EPOLLET&lt;/code&gt; mode won't tell you if something like that happens. It simply ignores that but if you're in the default mode (i.e., you don't have the flag added) you'll get a totally normal behaviour of epoll continuously waking you up when data is available.&lt;/p&gt;

&lt;p&gt;However, in this case the best thing is to use &lt;code&gt;EPOLLET&lt;/code&gt; with &lt;code&gt;EPOLLIN&lt;/code&gt; and &lt;code&gt;EPOLLOUT&lt;/code&gt;. And that is better explained with a visual 😁:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffufh3bu8n6dpz2ai7vmb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffufh3bu8n6dpz2ai7vmb.gif" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a ton of steps but believe me its easy once you understand it (wait for two way congestion control 😁)&lt;/p&gt;

&lt;p&gt;Step 1: the gateway sends data and the data is stored in the internal buffer of the socket and the EPOLLIN event is triggered for the gateway socket&lt;/p&gt;

&lt;p&gt;Step 2: the assigner reads all the data from the gateway and empties out the internal buffer and puts that data into its own buffer.&lt;/p&gt;

&lt;p&gt;Step 3: the assigner writes that data to the internal buffer of the worker socket.&lt;/p&gt;

&lt;p&gt;Step 4: more data comes from the gateway, and steps 1-3 repeat.&lt;/p&gt;

&lt;p&gt;Step 5: Now the worker socket's internal buffer is full hence &lt;code&gt;send&lt;/code&gt; returns -1 with &lt;code&gt;errno&lt;/code&gt; set as &lt;code&gt;EAGAIN&lt;/code&gt;. So now the assigner will simply remove the &lt;code&gt;EPOLLIN&lt;/code&gt; event from the gateway socket. So now even if the gateway sends the data, TCP will simply not allow data to flow because its own buffer is full.&lt;/p&gt;

&lt;p&gt;Step 6: The gateway is fast and won't stop so the gateway socket's internal socket gets full. But since the assigner does not read the data, TCP by default stops the data transfer until the data is read.&lt;/p&gt;

&lt;p&gt;Step 7: Once the worker reads something, its &lt;code&gt;EPOLLOUT&lt;/code&gt; event will trigger because the buffer was full and now it is not hence &lt;code&gt;EPOLLOUT&lt;/code&gt;. So now the assigner will first empty its own buffer (not visible in the diagram since it would have introduced a lot more steps) into the workers socket. Now if only some data goes in and the &lt;code&gt;send&lt;/code&gt; function again returns an error we don't have an option and we simply wait on the &lt;code&gt;EPOLLOUT&lt;/code&gt; event again. But if all the data is sent from the assigner's buffer, the assigner will read more data from the gateway socket. And this newly read data will also go to the worker socket.&lt;/p&gt;

&lt;p&gt;Step 8: This newly read data might not again be fully absorbed by the &lt;code&gt;send&lt;/code&gt; function hence we don't change any events on the sockets.&lt;/p&gt;

&lt;p&gt;Step 9: Now the case when we &lt;code&gt;read&lt;/code&gt; from the gateway socket and it returns a value less than the size of the buffer we specified. This means that the gateway has stopped sending the data from the other side and the gateway socket is completely drained. Now what? We simply add the &lt;code&gt;EPOLLIN&lt;/code&gt; event to the gateway socket. So now the gateway socket has the &lt;code&gt;EPOLLIN&lt;/code&gt; and &lt;code&gt;EPOLLOUT&lt;/code&gt; events attached to it.&lt;/p&gt;

&lt;p&gt;Step 10: Now keep on feeding the worker until the assigner's buffer isn't empty. Once the assigner's buffer is also empty we simply do nothing since that is the last time the &lt;code&gt;EPOLLOUT&lt;/code&gt; event will trigger. From then on the buffer will be at the minimum 1 byte not filled unless the gateway starts sending like a freak again 😂&lt;/p&gt;

&lt;p&gt;So that's all the steps the visual is trying to explain. Now you should have a question that why we're using &lt;code&gt;EPOLLIN&lt;/code&gt; and &lt;code&gt;EPOLLOUT&lt;/code&gt; instead of using only the events which are actually needed. So the gateway never uses &lt;code&gt;EPOLLOUT&lt;/code&gt; and the worker never uses &lt;code&gt;EPOLLIN&lt;/code&gt; then we should keep the other events for these sockets right?&lt;/p&gt;

&lt;p&gt;That's where the bi-directional congestion control comes into play 😁&lt;/p&gt;

&lt;h2&gt;
  
  
  Bi-directional Congestion Control?
&lt;/h2&gt;

&lt;p&gt;So now you know how we can do congestion control in a single direction but a node will always send and receive so things are never so simple 🫠&lt;/p&gt;

&lt;p&gt;First you can try to figure out the bi-directional congestion control mechanism yourself but I'll anyways explain it to you.&lt;/p&gt;

&lt;p&gt;So as you see in the diagram below you have two sockets each side:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fut6nav767ggv9nvstw2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fut6nav767ggv9nvstw2b.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you have to make sure congestion control in one direction does not interfere with the data flow of the other direction&lt;/p&gt;

&lt;p&gt;Firstly let's name the sockets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;code&gt;GIN&lt;/code&gt; - Gateway Data IN&lt;/li&gt;
&lt;li&gt; &lt;code&gt;GOUT&lt;/code&gt; - Gateway Data OUT&lt;/li&gt;
&lt;li&gt; &lt;code&gt;WIN&lt;/code&gt; - Worker Data IN&lt;/li&gt;
&lt;li&gt; &lt;code&gt;WOUT&lt;/code&gt; - Worker Data OUT&lt;/li&gt;
&lt;li&gt; &lt;code&gt;GTW&lt;/code&gt; - Gateway To Worker data flow&lt;/li&gt;
&lt;li&gt; &lt;code&gt;WTG&lt;/code&gt; - Worker To Gateway data flow&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Here &lt;code&gt;GIN&lt;/code&gt; and &lt;code&gt;GOUT&lt;/code&gt; are a single socket because TCP is a duplex connnection but for a better understand I have shown them separately. And the same goes for &lt;code&gt;WIN&lt;/code&gt; and &lt;code&gt;WOUT&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So now if the Worker has a lot of output to send to the gateway your &lt;code&gt;WIN&lt;/code&gt; socket will keep on throwing &lt;code&gt;EPOLLIN&lt;/code&gt; events whenever you finish reading it. But then at the same time if the &lt;code&gt;WOUT&lt;/code&gt; was full and you've kept only &lt;code&gt;EPOLLOUT&lt;/code&gt; then you'll be in trouble because then you won't receive &lt;code&gt;EPOLLIN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So there is a clever strategy I developed on my own (yeah, this time no gemini brainstorming sessions 😂). You always keep &lt;code&gt;EPOLLOUT&lt;/code&gt; on all the &lt;code&gt;OUT&lt;/code&gt; sockets. So this means we have &lt;code&gt;EPOLLOUT&lt;/code&gt; on &lt;code&gt;WOUT&lt;/code&gt; and &lt;code&gt;GOUT&lt;/code&gt;. Now you should ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why meet why?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is because having &lt;code&gt;EPOLLOUT&lt;/code&gt; along with &lt;code&gt;EPOLLET&lt;/code&gt; gives you a solid advantage to handling bi-directional congestion control. Firstly &lt;code&gt;EPOLLOUT&lt;/code&gt; is only ever triggered when the socket goes from totally full to a not full state. So you won't be handling the &lt;code&gt;EPOLLOUT&lt;/code&gt; event when some data goes out every time but only when the socket was full and not has at mininum a single byte of free space.&lt;/p&gt;

&lt;p&gt;So now that &lt;code&gt;EPOLLOUT&lt;/code&gt; is not going anywhere the only event we will ever add/remove is &lt;code&gt;EPOLLIN&lt;/code&gt; (&lt;code&gt;EPOLLET&lt;/code&gt; is the default, like &lt;code&gt;EPOLLOUT&lt;/code&gt; it won't go anywhere 😁). So the advantage of only ever changing &lt;code&gt;EPOLLIN&lt;/code&gt; is that if I remove the &lt;code&gt;EPOLLIN&lt;/code&gt; from &lt;code&gt;WIN&lt;/code&gt; and wait for &lt;code&gt;GOUT&lt;/code&gt;'s &lt;code&gt;EPOLLOUT&lt;/code&gt; to trigger, I can still handle &lt;code&gt;EPOLLIN&lt;/code&gt; from &lt;code&gt;GIN&lt;/code&gt; or wait for &lt;code&gt;WOUT&lt;/code&gt;'s &lt;code&gt;EPOLLOUT&lt;/code&gt; without having to worry about what the other side is doing.&lt;/p&gt;

&lt;p&gt;Isn't that a great advantage? I mean for my case it works pretty well 🫠&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's code it
&lt;/h2&gt;

&lt;p&gt;So for a bi-directional congestion control mechanism I am not sure if a visual will help or just leave you confused but here it is anyways 🙃&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuiu60ytiobcip0ikheks.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuiu60ytiobcip0ikheks.gif" alt=" " width="799" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This two way congestion control is working in a similar way to the one way congestion control except now its happening at two places simultaneously 😵&lt;/p&gt;

&lt;p&gt;Now its easier to see this in code. So first let's assume some things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;There is a socket named &lt;code&gt;w&lt;/code&gt; and a socket named &lt;code&gt;g&lt;/code&gt; and in here both are TCP sockets so &lt;code&gt;WIN&lt;/code&gt; and &lt;code&gt;WOUT&lt;/code&gt; both are &lt;code&gt;w&lt;/code&gt; itself and similarly &lt;code&gt;GIN&lt;/code&gt; and &lt;code&gt;GOUT&lt;/code&gt; both are &lt;code&gt;g&lt;/code&gt; itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Both the sockets are added to a &lt;code&gt;epoll&lt;/code&gt; loop and the loop is configured in a way that it runs either of the two functions on any event received and also passes the events down&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;resetEpollEvent&lt;/code&gt; is a function which takes in the socket and the new events to be added to the socket&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So first we write the gateway handler (&lt;code&gt;EPOLLIN&lt;/code&gt; for now):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;handle_gateway&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;EPOLLIN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// data received on g&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;sent_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sent_size&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// all data was not sent, the buffer is full!&lt;/span&gt;
            &lt;span class="n"&gt;resetEpollEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EPOLLOUT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EPOLLET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;size_to_send&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;sent_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And similarly you can guess the &lt;code&gt;EPOLLIN&lt;/code&gt; branch for the worker handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;handle_worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;EPOLLIN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// data received on w&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;sent_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sent_size&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// all data was not sent, the buffer is full!&lt;/span&gt;
            &lt;span class="n"&gt;resetEpollEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EPOLLOUT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EPOLLET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;size_to_send&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;sent_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now these were for the &lt;code&gt;EPOLLIN&lt;/code&gt; event but now let's write the gateway to handle the &lt;code&gt;EPOLLOUT&lt;/code&gt; event as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;handle_gateway&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;EPOLLOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// now g can be fed some data&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size_to_send&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;size_to_send&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// all data was sent! take more and send&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sent_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;sent_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sent_size&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// the buffer is full again!&lt;/span&gt;
                    &lt;span class="n"&gt;size_to_send&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sent_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="c1"&gt;// here max function is implicitly declared and its purpose is to keep sent_size as a minimum 0 in cases where sent_size might become -1&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// yay! all data was sent!&lt;/span&gt;
                &lt;span class="n"&gt;resetEpollEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EPOLLIN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EPOLLOUT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EPOLLET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// if the size does not match what we want to send, then just keep waiting again&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I know its a bit longer code than what I wrote for &lt;code&gt;EPOLLIN&lt;/code&gt; but I assure you it is worth the dive 😁&lt;/p&gt;

&lt;p&gt;And now you should try writing the code for the worker's &lt;code&gt;EPOLLOUT&lt;/code&gt; branch yourself (Hey, I'm not lazy 😑)&lt;/p&gt;

&lt;p&gt;Apart from the &lt;code&gt;EPOLLIN&lt;/code&gt; and &lt;code&gt;EPOLLOUT&lt;/code&gt; events you also have 3 events to tell you that the connection is cut &lt;code&gt;EPOLLRDHUP&lt;/code&gt;, &lt;code&gt;EPOLLHUP&lt;/code&gt; and &lt;code&gt;EPOLLERR&lt;/code&gt; these three together can detect almost any kind of connection cuts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;EPOLLRDHUP&lt;/code&gt; detects if a socket is closed from the other side of the network as in using the &lt;code&gt;shutdown&lt;/code&gt; function which I think no one generally uses 😂. If this event occurs, your socket is writable but not readable and the writability is local, the peer won't be able to read what you wrote if it has closed its reading end.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;EPOLLHUP&lt;/code&gt; also detects if a socket is closed from the other side but this event detects any errors from the socket and if this event happens then your socket is neither readable nor writable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;EPOLLERR&lt;/code&gt; detects some error that happened on the socket. Yeah that's it 😂&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now this was congestion control and tcp packet parsing but both aren't independent, you'll have to handle both together so the parsing happens on the data that comes from the data flow mechanism which also handles congestion inside itself 🫠&lt;/p&gt;

&lt;p&gt;But now that you do know the concept this should be much easier. And yeah I struggled to come up with the idea first and then struggled more to implement it but then combining both seemed trivial once I had them independently done.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I can do it, you can too!&lt;/p&gt;

&lt;p&gt;— Some genius (Me 😜)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just joking! The parsing and congestion control should mostly never overlap since congestion control is for a middleman like an assigner and parsing is for a consumer like a worker or a producer like a gateway (could be the other way round too). A consumer always consumes at its own pace and a producer produces at its own pace and hence the middleman needs congestion control.&lt;/p&gt;

&lt;p&gt;In my case the worker (consumer) uses a blocking socket hence even if it is slow or fast does not matter since it will experience time glitches which are fine in my case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you did not get confused and got to learn something good from this blog but I'm happy to answer any questions you face in the chats.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer: Meet can make mistakes, always verify with someone/something&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The packet parsing was a bit trivial once I added the size member to the head of the struct. But figuring out the congestion control mechanism demanded me to look into TCP's congestion control (which was of very little help) and in general congestion control and mix them up and create a new mechanism. But then that mechanism was, I'd say, not so "good" hence I threw it in the trash and explored distributed algorithms like paxos, raft and distributed systems like bit torrent and one morning my brain wished me a "Good Morning" with this idea and I was surprised I could think of such a good mechanism. (Yeah I'm proud of my creation, for the first time though 😁)&lt;/p&gt;

&lt;p&gt;Currently I'm also new to the distributed realm and you're a better expert than me so if you spot any mistake in my approach or anything please do let me know, I'm more than happy to recreate a new mechanism from scratch and throw this in the trash too 😂 but the new one should be worth it!&lt;/p&gt;

&lt;h2&gt;
  
  
  So, what's next?
&lt;/h2&gt;

&lt;p&gt;Currently I'm learning some Rust cause I heard it is a harder language than C and I just want to see exactly how hard it is. I'm starting with the fundamentals and mostly using the book &lt;a href="https://doc.rust-lang.org/book/" rel="noopener noreferrer"&gt;The Rust Programming Language&lt;/a&gt; which is not exactly a book but a webpage. And I think its pretty awesome since this is the first community I saw making such an amazing and deep "documentation".&lt;/p&gt;

&lt;p&gt;And the next time I'm going to discuss on linux containers and how to use OverlayFS on the containers. Also I "might" discuss about GARP and OPFS but all depends on time 😁&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbpo2qtdmet6fk0r0k0j.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbpo2qtdmet6fk0r0k0j.gif" alt=" " width="466" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>c</category>
      <category>linux</category>
      <category>networking</category>
      <category>systemarchitecture</category>
    </item>
    <item>
      <title>Monoliths, Mutexes, and Mistakes: 3 System Design Problems I Tried to Solve from Scratch</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Sat, 04 Jul 2026 13:46:39 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/monoliths-mutexes-and-mistakes-3-system-design-problems-i-tried-to-solve-from-scratch-25n7</link>
      <guid>https://dev.to/geniusmind9999/monoliths-mutexes-and-mistakes-3-system-design-problems-i-tried-to-solve-from-scratch-25n7</guid>
      <description>&lt;p&gt;This weekend me and my two other friends sat down again for discussing system design.&lt;/p&gt;

&lt;p&gt;If you're a new reader, me and my two other friends have made a weekly routine of meeting online every weekend and proposing ideas for one system design question. And possibly implementation which is a real rarity 😂&lt;/p&gt;

&lt;p&gt;I have 3 problems to share with you today and all the three did make me think deep into this domain. So let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Design Synchronized Queue Consumers&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/queue-consumers.md" rel="noopener noreferrer"&gt;This&lt;/a&gt; was the first one, and its description was quite confusing at first. In fact one of us misinterpreted the entire problem and built something the problem never asked... and yet it had a lot of new things to learn and a lot of places to criticize 😌&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Core Requirements:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Only one consumer consumes an element from the queue at any moment&lt;/p&gt;

&lt;p&gt;If two consumers trying to fetch the head of the queue, one has to wait while other finishes&lt;/p&gt;

&lt;p&gt;Queue is a black box and cannot be altered&lt;/p&gt;

&lt;p&gt;Throughput of the system does not matter&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this seems simple enough but it was difficult deep inside. Because here mutexes or locks would spike up the latency a ton.&lt;/p&gt;

&lt;p&gt;The real solution which only one of us managed to implement was &lt;strong&gt;Remote Locking&lt;/strong&gt;, this comes from a distributed context and it is an in built feature of &lt;strong&gt;Redis&lt;/strong&gt;. This mechanism allows multiple workers to work simultaneously on a resource which means it allows horizontal scaling which in turn makes it perfect for flexible systems which can control the number of simultaneous workers working on the resource (similar to my CodeArena project 😁).&lt;/p&gt;

&lt;p&gt;And the good part is that remote locking has a negligible effect of horizontal scaling since it was built for it.&lt;/p&gt;

&lt;p&gt;But anyways, let's just focus on what I did, especially what I did wrong 😂&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff7ar4bnv0goocjeuhtgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff7ar4bnv0goocjeuhtgk.png" alt="Synchronized Queue Consumers Architecture" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of using a distributed architecture, I thought of going with a monolith this time, and it turns out I was totally wrong 🫠.&lt;/p&gt;

&lt;p&gt;So my idea was simple, I have a single queue inside the server (in-memory queue) which is shared by two processes/threads whatever you find is better according to the number of incoming requests.&lt;/p&gt;

&lt;p&gt;The red colored box is the process/thread which simply takes the first element from the queue and gives to the blackbox queue. In practice, this element should be a user connection say a HTTP request or something&lt;/p&gt;

&lt;p&gt;The green colored box is another process/thread which could be multiple in number and they accept the connection request of the user and add it to the in-memory queue.&lt;/p&gt;

&lt;p&gt;The blue box is the in-memory queue, I thought of implementing it as a bounded buffer but for that I need to know beforehand how many requests will come at peak time. So that was the first problem with this design, if the traffic spikes more than we expect, the queue will totally fail and old data gets over written which leaves a client hanging and later facing a timeout.&lt;/p&gt;

&lt;p&gt;The second issue are the mutexes on the queue. If I put the queue behind mutexes then the speed decreases due to the number of system calls made to the OS. I then had this idea of a per-element mutex but that would add a huge overhead of memory but it would surely increase the speed since it will rare that the green and red processes are on par with each other, one would naturally fall behind hence every mutex call won't actually wake up the kernel (the newer futexes (it is "futexes") in linux do that, and it blew my mind for the first time 😂) hence the time that is taken reduces drastically.&lt;/p&gt;

&lt;p&gt;So the conclusion? My system works at a smaller scale when you know the peak traffic numbers, otherwise it totally fails ✌️&lt;/p&gt;

&lt;h3&gt;
  
  
  TLDR;
&lt;/h3&gt;

&lt;p&gt;This design is simply a middle man design which uses an internal queue (with mutex insecurities) to pass a client to the black box queue 😂&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Design an Image Service&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/image-service.md" rel="noopener noreferrer"&gt;This&lt;/a&gt; was the second system design problem we solved. And it was quite a struggle 😁&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Core Requirements:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Upload &lt;strong&gt;5 million images&lt;/strong&gt; every hour from various clients and devices&lt;/p&gt;

&lt;p&gt;Serving images &lt;strong&gt;efficiently&lt;/strong&gt; to the rendering devices&lt;/p&gt;

&lt;p&gt;Provide &lt;strong&gt;analytics&lt;/strong&gt; around how images are requested from the systems&lt;/p&gt;

&lt;p&gt;Bandwith consumption should be &lt;strong&gt;near-optimal&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This design was a struggle because I initially chose to use a monolith (again, I know! 😂) and hit a road block and then shifted to a distributed system. In fact I even forgot CDNs both the times and did not use an object storage. I stored the images in the same servers which were storing the metadata and the list just goes on. But hey it had a high throughput 😅 until the other two people analyzed it...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0wtipat0sdzrm3yi5fhe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0wtipat0sdzrm3yi5fhe.png" alt="Image Service Architecture" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It seems to have a lot of components we could get rid of and a lot of "alien" components. This is because I wanted to &lt;strong&gt;DIY&lt;/strong&gt; it 😇&lt;/p&gt;

&lt;p&gt;Firstly those black boxes are just the bottom box duplicated across the globe totally independent of each other. Now that's clear I can move to the explaination 😂&lt;/p&gt;

&lt;p&gt;So inside every such black box the first thing the request hits is obviously a load balancer. Now there is a sneaky problem hidden in here and I solved it without having to change anything in the system, but let's see the original first. The load balancer routes the request to the server with the lowest current task and you ask how it will know the lowest task server? That small server in the corner does exactly that, it listens to messages from the servers about the number of task they have and it unicasts the address of the lowest loaded server directly to the load balancer (more specifically another process running on the same machine with a shared memory to the actual load balancer). Now the load balancer always sends the request to the lowest loaded server without having to calculate anything.&lt;/p&gt;

&lt;p&gt;Now let's come to the bugs, first the easy ones.&lt;/p&gt;

&lt;p&gt;Do normal load balancers like NGinx allow that kind of granularity? I am not so sure but probably yes. I was thinking that the organization would have their &lt;strong&gt;custom&lt;/strong&gt; load balancer sitting there 😌 which my friend ruled out because it increases development cost as well as maintenance cost 😵&lt;/p&gt;

&lt;p&gt;The second problem is what if someone from some other region wants to access an image stored in a region server very very far away?&lt;/p&gt;

&lt;p&gt;My solution - embed that directly in the image URL. So the image url is a lower case alphabetic string of length 8. It is made up like so "{RegionID}-{ImageID}". Here the RegionID is the id of the region and it can be kept as a map key pointing to the actual region's load balancer's address. And the ImageID is the ID of the image in the region's internal object database. So how much can this short string support? After calculating a split of 3 characters for RegionID and 5 characters for ImageID can support 1,000 regions each with 100,000 images in them. And this is an approximation, there can be vastly more regions and images per region.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you also use upper case letters, this length 8 string can support about 140 thousand regions and 380 million images per region, HUGE!! Just try that for alphanumerics 😉&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So now a load balancer just checks the first 3 characters of the image and knows if it forwards the request to one of its internal servers or some other regional server.&lt;/p&gt;

&lt;p&gt;But this solution had a ton of flaws which my other two friends covered up, but their designs were monoliths up to what I remember hence they too had their own share of problems 😁&lt;/p&gt;

&lt;h3&gt;
  
  
  TLDR;
&lt;/h3&gt;

&lt;p&gt;This is a "monolith-became-distributed" design which almost gave me a headache 😂. Every component in it is &lt;strong&gt;DIY&lt;/strong&gt; and hence it has its own set of problems. Internally it is a region wise distributed system with each node having an inner distributed server design governed by a load balancer and health checked by a small server. The load balancer also uses the image url to know which region the image originally belongs to.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Design the HashTag Service&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/hashtag-service.md" rel="noopener noreferrer"&gt;&lt;strong&gt;This&lt;/strong&gt;&lt;/a&gt; was the next system design question that stared me in the face. And this time I chose the distributed path directly (I am a "Dynamic Program-mer" after all 😁).&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Core Requirements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Extract&lt;/strong&gt; and &lt;strong&gt;manage&lt;/strong&gt; HashTags from all the uploaded photos&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 million&lt;/strong&gt; photos uploaded every hour&lt;/p&gt;

&lt;p&gt;Efficiently drive the HashTag page that shows:&lt;/p&gt;

&lt;p&gt;1. the hashtag&lt;/p&gt;

&lt;p&gt;2. the number of photos with that hashtags&lt;/p&gt;

&lt;p&gt;3. top 50 photos for that hashtag&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Honestly this one felt easy on the surface and was not so aggressive when I dug in, so I enjoyed this problem (or maybe the problem enjoyed me 👀, goes both ways you know 😂).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqd46nmyvyg6ox4ir1ok6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqd46nmyvyg6ox4ir1ok6.png" alt="HashTag Service Architecture" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Till now, I have always tried to do everything and every component &lt;strong&gt;DIY&lt;/strong&gt; but this time I used external services and already trusted databases because everytime introducing something new is just not worth it 😉&lt;/p&gt;

&lt;p&gt;So firstly this is also a distributed system and each of the servers are deployed across the globe. Each region node has an internal Apache Cassandra instance running in it. Why Apache Cassandra? Because it prioritizes high availability, eventual consistency and can handle huge write spikes easily.&lt;/p&gt;

&lt;p&gt;Internally Apache Cassandra is a P2P distributed network, each piece of data is stored in three nodes. So how it works is like this, you contact any node in the system, it uses a concept of sharding in which you split the data into buckets to make it totally deterministic. So the node you communicate with is called the &lt;strong&gt;coordinator&lt;/strong&gt; node just for that read/write operation. The coordinator node communicates with the nodes which need to store the data and also coordinates with those who have the data to be read. It merges the outputs and then gives it back to you. Simple, elegant yet difficult 😅&lt;/p&gt;

&lt;p&gt;The other component except Apache Cassandra is a server called &lt;strong&gt;Master&lt;/strong&gt; which is responsible for the display of top 50 images. Now each master queries its own Apache Cassandra database using a CQL query and gets their own version of top 50 images, then they sync across the globe (it is as bad as it sounds 😅) and merge everything and cache it for sometime.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note on CQL: Cassandra is a wide column database with its own language - Cassandra Query Language, think of it as SQL level 1, limited to basic queries without any kind of joins or complex aggregations&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now I know there are loopholes here, the first and foremost is stale data. The top 50 data is going to be stale since there are 1400 images coming in every second from everywhere in the system the monitors can at max cache the result for about 1 second or lower depending on what you want to prioritize Consistency or Availability. If you do prioritize Consistency then the latency spikes up and otherwise its stale data.&lt;/p&gt;

&lt;p&gt;The second problem is how to efficiently merge the data. If you have read my previous blogs, you'd know I mentioned about a very twisty idea and while explaining how it would work I wrote "LSM Tree". So that is the key here, we could use LSM Trees for syncing between the nodes, every master node creates an LSM tree of their data sends it to the other masters and merges its LSM tree with all the other ones it receives. This guarantees deterministic output even when the system is under huge load.&lt;/p&gt;

&lt;p&gt;The other two of my friends built a monolith and I saw a problem in one of the monoliths that surprisingly was not much of a problem in Cassandra. So they used a normal Postgres or SQL database and the problem with those databases is that they use locks and locks tend to slow down reading.&lt;/p&gt;

&lt;p&gt;This use case is a write heavy use case, but it also needs frequent reading just not as frequent as writing (maybe once per second?). So now what does a database do when 1400 entries are written down every second using a write lock passed around and almost never actually released? It would starve the reader! And what happens when this happens at a scale in a monolith? The read latency spikes up fast hence the advantage a monolith gives of consistency and availability together against the distributed architecture is simply not so interesting now that we consider the network latency, read latency and physical constraints of the machine itself.&lt;/p&gt;

&lt;p&gt;Now why does this not happen in Apache Cassandra? Because Apache Cassandra is internally using a distributed architecture you can read and write to it at the same time under huge load without it actually breaking down! I mean of course the reads do slow down the writes by consuming nodes but that happens once every 1400 writes which I think is a good tradeoff here.&lt;/p&gt;

&lt;p&gt;But the better approach according to me should be a monolith using Apache Cassandra as its database, this would allow fast reads, fast writes and we only have the network latency rising as a problem. No syncs, no LSMs, no database lock latency, pure speed and some better tradeoffs 😌&lt;/p&gt;

&lt;h3&gt;
  
  
  TLDR;
&lt;/h3&gt;

&lt;p&gt;This is a good system which turned difficult to build and handle a bit too fast 😅. It uses a Apache Cassandra database and a master node for each geographic node. Apache Cassandra allows almost parallel reads and writes while the master node allows global deterministic sync to top 50 images. This one uses CDNs and external Object Storages though 😂&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Next we are planning to tackle &lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/onepic.md" rel="noopener noreferrer"&gt;this&lt;/a&gt; problem "&lt;strong&gt;Design OnePic&lt;/strong&gt;". And I think I am going decentralized on this one. Haven't had a decentralized architecture in a long time 😂&lt;/p&gt;

&lt;p&gt;If you have made it till here, I would like to inform you that I have changed my blogging style from an &lt;strong&gt;Monolith&lt;/strong&gt; style to a &lt;strong&gt;Distributed&lt;/strong&gt; style, all my blogs have exactly one thing they discuss about, no messy blog discussing 10 topics all at once, one blog for exactly one topic so it is easier for you read what you like and easy for me to know what you like 😁&lt;/p&gt;

&lt;p&gt;See you in the next blog, Byee!&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Writing an event loop in C is easy, Until...</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Fri, 03 Jul 2026 09:08:39 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/writing-an-event-loop-in-c-is-easy-until-4m87</link>
      <guid>https://dev.to/geniusmind9999/writing-an-event-loop-in-c-is-easy-until-4m87</guid>
      <description>&lt;p&gt;I wrote an event loop using epoll in C this week and I was surprised at how easy it was! But... TCP did not like the idea 🫣&lt;/p&gt;

&lt;p&gt;I am 2 weeks late, but this time I have written an event loop in C. NodeJS and Nginx both have similar event loops running inside them. In fact Nginx's event loop is much much faster since it avoids system calls as much as possible. And I wrote the event loop before I came to know of this.&lt;/p&gt;

&lt;p&gt;So if you are a new reader, I along with some more friends am building CodeArena, a place for students to learn programming and complete assignments given by the professors and the Teaching Assistants. And my job is to design a system which can run the student's code on a remote server because apparently it is hard to run it on their browser 😂&lt;/p&gt;

&lt;p&gt;So my initial (and naive) approach was to use pthreads for everything. Literally, you want to send a message? A pthread, you want to hold elections, boom two more pthreads at your service. But... (Yeah there's always a "But...")&lt;/p&gt;

&lt;p&gt;This created a huge problem - mutexes! I love what mutexes do, but they involve a ton of system calls making the thread approach very very inefficient 😓&lt;/p&gt;

&lt;p&gt;So to solve that, I brainstormed with gemini, and after hours of nice brainstorming I came to the event loop. I googled what it was how it fitted to my use case, what were the tradeoffs and should someone as naive as me use it. To my surprise, this is the first time something actually happened to fit right into my usecase!&lt;/p&gt;

&lt;p&gt;An event loop can be explained as simply a waiter in a restaurant which only takes your order if you raise your hand, it juggles multiple programs on its own without calling the OS for help in context switching. These "programs" are mostly functions, hence the usage is super duper simple.&lt;/p&gt;

&lt;p&gt;But is the implementation also that simple? Surprisingly yes! You just have to read the man pages of 4 c functions and you are done (those 4 will take to 4 more but I focus on the positive part, so let's stick to the original 4 right now 😂).&lt;/p&gt;

&lt;p&gt;Now once the loop was implemented I started rewriting my c code to use the event loop. I created tons of new functions, each doing its own job. For a minute it felt like using NodeJS with a C syntax.&lt;/p&gt;

&lt;p&gt;That was until I hit TCP 🫣. TCP has its own rabbit holes and you might wanna be careful when trying it. I mean TCP can be non blocking but for it to be non blocking you'll have to have accept and connect in a non-blocking fashion, and that requires more work. I did try it, but I am going too slow here due to a superpower. When I face hard things, I want to leave them 😵&lt;/p&gt;

&lt;p&gt;A lot of times I thought, why not just give this to a LLM and just understand the concept? I mean that should be valid right? But then I force myself to do it, not because AI usage is not good or I won't learn anything when using AI but because whatever I do myself will become a part of my memory and when I actually require it sometime in the future I would know where to find things or where to start looking instead of straight up opening the LLM and delegating the task to it.&lt;/p&gt;

&lt;p&gt;I have completed writing the monitor node (for now 😂) and I am writing the assigner node, but TCP is in the way 🫥 and I am trying to tackle it...&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I get some CODE?
&lt;/h2&gt;

&lt;p&gt;So this is the part when I share the code for the event loop. You can also find it on github once my repository becomes public.&lt;/p&gt;

&lt;p&gt;To write this code, you might need to go through these man commands (atleast I went through these):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;man 7 epoll
man epoll_create1
man epoll_event
man epoll_wait
man epoll_ctl
man 2 fcntl
man 2 &lt;span class="nb"&gt;time
&lt;/span&gt;man 2 gettimeofday
man ctime
man clock_gettime
man timerfd_settime
man timer_create
man timerfd_create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the code is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;startLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;epollfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;max_events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;epoll_event&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;max_events&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EPOLLIN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EPOLLRDHUP&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EPOLLET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;va_list&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;va_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;va_arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epoll_ctl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epollfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EPOLL_CTL_ADD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"monitor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Failed to add fd to interest list&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;va_end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// epoll_wait should listen for ev events&lt;/span&gt;
        &lt;span class="c1"&gt;// with a max of 6 events since 2 sockets can have 3 events each&lt;/span&gt;
        &lt;span class="c1"&gt;// so even if all occur simultaneously all the events will be caught&lt;/span&gt;
        &lt;span class="n"&gt;nfds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;epoll_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epollfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nfds&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"async loop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="s"&gt;"epoll_wait returned invalid number of ready sockets&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yep... This is the whole code. But if you were to write this on your own honestly it would take some time and some man pages to write this. There's a lot of things to take care in here and I'll explain them.&lt;/p&gt;

&lt;p&gt;Firstly, look at what socketDetails is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;socketDetails is a struct containing the file descriptor of the socket, any additional data you might want to pass in to the handler function (for context, you'll know what I mean later) and a handler function to call when the file descriptor has an event.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explaining the Code:
&lt;/h3&gt;

&lt;p&gt;Let's start slow&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;startLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;epollfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;max_events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;...&lt;/code&gt; are just variadic function arguments in C. I also got to know them due to this project. So this syntax allows you to pass in any number of arguments to your c function but you have to handle the segmentation fault errors. It does not tell you if you reached the end of the arg list, you as a programmer have to take care by passing an explicit number to indicate the number of arguments coming in (here &lt;code&gt;nfds&lt;/code&gt; is doing that)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;epollfd&lt;/code&gt; is just a file descriptor created like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;epollfd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;epoll_create1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but this is outside the function so that other functions can access it when their file descriptor receives an event.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;max_events&lt;/code&gt; is the maximum events &lt;code&gt;epoll_wait&lt;/code&gt; can hand you. If there are more events, you get those remaining ones in the next &lt;code&gt;epoll_wait&lt;/code&gt; call, just a small limiting system to help the programmer and the kernel together.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nfds&lt;/code&gt; is the count of how many arguments are passed to the function&lt;/p&gt;

&lt;p&gt;The next is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;epoll_event&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;max_events&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EPOLLIN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EPOLLRDHUP&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EPOLLET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this code snippet does two things, firstly it declares an epoll event and then declares an array of events. the variable &lt;code&gt;ev&lt;/code&gt; is used to add a file descriptor along with the events to monitor in the interest list of the program internal to the OS.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;ev&lt;/code&gt; represents a single event. And &lt;code&gt;events&lt;/code&gt; is an array which is filled by the OS when an event occurs on any file descriptor in the programs interest list.&lt;/p&gt;

&lt;p&gt;The second line is simply setting what events we want to monitor on our file descriptors. Since all the sockets I pass it initially are UDP sockets, I tell epoll to monitor &lt;code&gt;EPOLLIN&lt;/code&gt; event which tells me if the socket is ready to read. I also look for the &lt;code&gt;EPOLLRDHUP&lt;/code&gt; event which simply tells me if the connection is broken from the other side (not useful for UDP but I still kept it if I change my mind to even add TCP sockets during the initialization 😅).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;EPOLLET&lt;/code&gt; event is an interesting one, it was introduced in a new version of epoll and it stands for "Edge Triggered EPOLL".&lt;/p&gt;

&lt;p&gt;For an easier explanation, picture this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;epoll_wait&lt;/code&gt; wakes up to find 1024 bytes of data in socket A. Currently it is in its default mode "Level Triggered" (it does not have an explicit flag like &lt;code&gt;EPOLLET&lt;/code&gt;). So a function is called which reads 1000 bytes of data from socket A and again calls &lt;code&gt;epoll_wait&lt;/code&gt;. But since 24 bytes are still in the socket buffer, &lt;code&gt;epoll_wait&lt;/code&gt; instantly returns control to the function. It won't actually sleep until all the data in socket A is read.&lt;/p&gt;

&lt;p&gt;Now let's see &lt;code&gt;EPOLLET&lt;/code&gt;, initially socket A was empty and it receives some data. Now as expected &lt;code&gt;epoll_wait&lt;/code&gt; wakes up and passes control to the function. Now is the important part, if the function just reads 1000 bytes and again calls &lt;code&gt;epoll_wait&lt;/code&gt;, then this function will never be called again for socket A. Edge Triggered epoll has a strict rule, it only wakes up if the socket &lt;strong&gt;was empty&lt;/strong&gt; and now &lt;strong&gt;has data&lt;/strong&gt;. It won't wake up if there &lt;strong&gt;was data&lt;/strong&gt; unread and more &lt;strong&gt;data comes&lt;/strong&gt; in. This means you have to read a socket until you hit the &lt;code&gt;EAGAIN&lt;/code&gt; error and if you don't, you are doomed (not literally though 😂)&lt;/p&gt;

&lt;p&gt;Now the next snippet is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;    &lt;span class="kt"&gt;va_list&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;va_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;va_arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epoll_ctl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epollfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EPOLL_CTL_ADD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"monitor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Failed to add fd to interest list&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;va_end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet parses the arguments passed into the variadic function.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;va_list&lt;/code&gt; is a type which will contain all the arguments passed to the function&lt;/p&gt;

&lt;p&gt;&lt;code&gt;va_start&lt;/code&gt;, &lt;code&gt;va_arg&lt;/code&gt; and &lt;code&gt;va_arg&lt;/code&gt; are just C macros. &lt;code&gt;va_start&lt;/code&gt; tells the compiler the address of the last named argument. &lt;code&gt;va_arg&lt;/code&gt; simply puts data equal the size of the passed type into the left hand side variable (which is a pointer in this case). &lt;code&gt;va_end&lt;/code&gt; is simply the cleanup guy, it cleans up any memory allocated by &lt;code&gt;va_start&lt;/code&gt; and also deallocates &lt;code&gt;va_list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next I simply attach the pointer to the data of the epoll event. This helps me know what to do when a specific socket receives an event (much better than a if-else or switch-case ladder). And after adding the context, I add this event to the interest list of the process for the OS to refer.&lt;/p&gt;

&lt;p&gt;That's it, this snippet seems big, but it does not do a lot&lt;/p&gt;

&lt;p&gt;The next snippet is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// epoll_wait should listen for ev events&lt;/span&gt;
        &lt;span class="c1"&gt;// with a max of 6 events since 2 sockets can have 3 events each&lt;/span&gt;
        &lt;span class="c1"&gt;// so even if all occur simultaneously all the events will be caught&lt;/span&gt;
        &lt;span class="n"&gt;nfds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;epoll_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epollfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nfds&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"async loop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="s"&gt;"epoll_wait returned invalid number of ready sockets&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;socketDetails&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, too big? Yes. Does too much? NO.&lt;/p&gt;

&lt;p&gt;So firstly the loop is obvious I guess, the name is "event loop" 😂&lt;/p&gt;

&lt;p&gt;&lt;code&gt;epoll_wait&lt;/code&gt; is the function that wakes up when some file descriptor receives an event. And &lt;code&gt;ndfs&lt;/code&gt; contains the number of events to process, so we have to loop for each event.&lt;/p&gt;

&lt;p&gt;The rest is trivial I guess, when processing an event in the for loop, just call the handler and pass in the socketDetails pointer.&lt;/p&gt;

&lt;p&gt;And as always, but... &lt;code&gt;epoll_wait&lt;/code&gt; returns -1 if you press &lt;code&gt;Ctrl + C&lt;/code&gt; or give any signal to the program. I just wanted the program to end on any signal so I kept &lt;code&gt;ndfs &amp;lt;= 0&lt;/code&gt;, you could keep it &lt;code&gt;ndfs &amp;lt;= -1&lt;/code&gt; if you don't want the event loop to get interrupted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you write your own Event Loop?
&lt;/h2&gt;

&lt;p&gt;Of course! Now that you have seen the code and probably referred the man pages, you can write the event loop faster than just starting from scratch. But don't you trust me blindly, I might be wrong at a ton of places which even I might not know (yet 😂) so keep in mind:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Meet is Human and can make mistakes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(If you did not catch it, that is written at the bottom of every gemini chat, just a small joke 🫠)&lt;/p&gt;

&lt;h2&gt;
  
  
  So what now?
&lt;/h2&gt;

&lt;p&gt;Now I will push my mind to write the non blocking tcp code and complete the assigner and, you know it, "stay more consistent on blogging" 😂&lt;/p&gt;

&lt;p&gt;And this is just one part, this time I have decided to split my blogs into parts so that is writable for me, and readable for you kinda a microservices architecture where everything is independently scalable (no need to point out the cons, I know it 😂🫣)&lt;/p&gt;

</description>
      <category>systemsprogramming</category>
      <category>c</category>
      <category>learninginpublic</category>
    </item>
    <item>
      <title>From Slack Clones to Data Mules: My Descent into System Design Madness</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Fri, 12 Jun 2026 14:28:05 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/from-slack-clones-to-data-mules-my-descent-into-system-design-madness-3l8h</link>
      <guid>https://dev.to/geniusmind9999/from-slack-clones-to-data-mules-my-descent-into-system-design-madness-3l8h</guid>
      <description>&lt;p&gt;According to the CAP theorem, I sacrificed Consistency for Availablilty! I have some good content to share today and much better than last time. This is what caught me up for a long long time.&lt;/p&gt;

&lt;p&gt;So last time I came up with a system design which was decentralized but this time I have 4 more designs for 4 different use cases. One of them combines the benefits of the centralized world while being decentralized in nature. I know it sounds weird, but it kinda resembles an architecture of that kind, and I did not take help of any external sources except my own brain (I wish I had a chip installed, I could just lie this way 😂)&lt;/p&gt;

&lt;p&gt;And today I am also planning to share a very twisty problem which might seem like another tuesday for someone building at scale, but for someone like me who is still learning the art, I was totally lost in the ideas... which were totally wrong at first but then slowly started clicking together 🤒. That problem involves me introducing HLC's and BitTorrent just for helping WebRTC. Sounds weird? It is! 😂&lt;/p&gt;

&lt;p&gt;And finally I have some micellaneous stuff, sort of life updates but technical. I want to share some repositories I found and were shared with me, plus something about my freelance work.&lt;/p&gt;

&lt;p&gt;Also I have a confession, I am kinda losing interest after completing half the local cloud project. I just don't know why, but it feels like this project just held up too long but... I think I'm not gonna let myself lose interest in this project. But there's nothing I can do except just continue the implementation and hope for the best.&lt;/p&gt;

&lt;p&gt;So let's get started!&lt;/p&gt;




&lt;h2&gt;
  
  
  The Local Cloud
&lt;/h2&gt;

&lt;p&gt;The last time I wrote a blog the empty nodes elected a monitor and the monitor just sent and received heartbeats, nothing else. The monitor did not store the information of the heartbeats neither did it have a sync protocol for multiple monitors.&lt;/p&gt;

&lt;p&gt;This new version has a defined limit on the number of nodes a monitor can hold. So all the monitors listen on port 8000 for broadcast messages. Now suppose there is an empty node trying to find the nearest monitor, that nodes sends the message and the first monitor to reply is the monitor it will talk to. But that was the happy path...&lt;/p&gt;

&lt;p&gt;Now comes the failure path, suppose this happens and I have a 100 nodes of which just one is a monitor, now that monitor will get overloaded as more and more empty nodes join in right? So how do we solve this?&lt;/p&gt;

&lt;p&gt;The easiest solution I could think of in a mess I created was for the monitor to simply not reply if it's capacity is full. So a monitor can only hold 5 nodes suppose and it has 5 nodes sending it heartbeats via unicast. All is working well right now. But then a 6th node joins in, now that node sends a broadcast signal but the only monitor does not reply because it is already at max capacity. Hence the 6th node becomes the new monitor by electing itself. Now any new node joining in will get a reply from this new monitor until a node from the old monitor fails and stops sending it heartbeats.&lt;/p&gt;

&lt;p&gt;But apart from this feature, the monitors can also sync their data giving each monitor a good view of the entire system. They sync only 5 numbers, the number of gateways, assigners, monitors, workers and empty nodes. Now that each node has a bird view of the system, if any of these numbers fall below their required minimum (for example gateway becomes 0) then the monitors elect one among them to do the promotion process. The promotion process just means promoting nodes in some hierarchy to fill up the minimum requirement of each node type.&lt;/p&gt;

&lt;p&gt;Currently the monitors do not have the promotion logic yet, but they can elect one among them for starting the process. That elected monitor just says "I will promote nodes" and gets to its usual work again 😂&lt;/p&gt;

&lt;p&gt;So next I'm planning to add this promotion logic and then I'll start writing these other nodes, starting with the gateway then the assigner and last but not the least the worker node. This way I am planning to connect with new bugs and headaches which will help me in the future! (High hopes 🤞)&lt;/p&gt;




&lt;h2&gt;
  
  
  System Design
&lt;/h2&gt;

&lt;p&gt;So this time I have done 4 system designs since I had a backlog 😂&lt;/p&gt;

&lt;h3&gt;
  
  
  Airline Check-in System
&lt;/h3&gt;

&lt;p&gt;The first was &lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/airline-checkin.md" rel="noopener noreferrer"&gt;this&lt;/a&gt;. The problem statement in short is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make a ticket booking system that is highly available, consistent and should handle a load of 100 passengers per flight.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The problem statement also said a lot more things than I have written here, but this is mostly what it was.&lt;/p&gt;

&lt;p&gt;Hence I came up with this design which, as I told was a combination of centralized and decentralized worlds. So this architecture is not complete, neither is it robust but its just me trying to explore something out of the box and also learn. I would be so glad if someone could actually point out a pretty huge bug hiding in plain sight (without the use of LLMs I guess? 😂).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F53qkdsr8cy7fvmjd1y8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F53qkdsr8cy7fvmjd1y8j.png" alt="Airline Checkin System Architecture" width="800" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So this looks simple but the explaination is a bit complicated. So on the right if you see there's this client server architecture where in a client is redirected to a server using a load balancer. There can be multiple such load balancers since they are kinda independent. This is a decentralized system this way. The load balancers only need to know one thing — which server handles which flight.&lt;/p&gt;

&lt;p&gt;Yeah, this is the thing that makes my system centralized. So suppose there is a flight from place A to place B, then there will be a server allocated explicitly to that flight. And that server will be pysically present somewhere near the midpoint of place A and place B. So any load balancer getting a request for the flight from A to B will always redirect to the dedicated server. And due to this flight-server mapping this system becomes centralized around the allocated server. So latency could spike if you're at place C trying to book a flight for place A to B but not if you're staying near A and B or maybe closer to the mid-point.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL Backed Key Value Store
&lt;/h3&gt;

&lt;p&gt;Actually this was a problem similar to Redis but I thought let's not look into how Redis does it, so first I designed my system then looked at Redis. And surprisingly (or by pure luck 😂) one of my design decision was actually implemented by Redis.&lt;/p&gt;

&lt;p&gt;This was the &lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/sql-kv.md" rel="noopener noreferrer"&gt;problem statement&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Design a KV Store built on top of a SQL (relational) database. The store exposes APIs to &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;DEL&lt;/code&gt; keys. Along with these core functiona, there should be an API to set &lt;code&gt;TTL&lt;/code&gt; to an existing key, post which the key is auto-deleted from the store. Scale this KV store &lt;strong&gt;1 million&lt;/strong&gt; concurrent API calls and a total storage of &lt;strong&gt;5000 TB&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this was my design:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fib80x5ap5srt7fhk15o0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fib80x5ap5srt7fhk15o0.png" alt="SQL Backed Key Value Store Architecture" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So on the left is a normal distributed architecture as you'd expect. Nothing fancy here, clients connect to the server via a load balancer. But the new thing I introduced here are dynamic buckets.&lt;/p&gt;

&lt;p&gt;So let's talk about databases first, the database isn't a single machine, it can be split up into how many ever different machines you want (according to how much you want to spend).&lt;/p&gt;

&lt;p&gt;Next layer is called the Dynamic Bucket layer and it consists of not so resource hungry servers. These servers get a request from the client via a load balancer and do the GET, PUT or DEL requests on the databases. These servers have a map or dictionary if you're more familiar with python. this map has all the keys attended by the server and which key is stored on which database. It also stores which keys are TTL keys. Now when a server has a lot of keys in it, say 10,000 keys, then the server will do something amazing, it will delegate half of its task to an idle server. This gives a nice splitting effect based on the actual work instead of just ranges.&lt;/p&gt;

&lt;p&gt;The dynamic bucket layer initally consists of just 1 active server and the rest will be idle servers. The idle servers do literally nothing. One important thing to know is that these servers will store only the hash of the key and not the key entirely since a key could ideally be very very long. So when an active server is full, it will slice its map into half (actually half, it will be maintaining a sorted array of key hashes side by side and when the time to split comes, the mid point of the array is taken and any hash less than that will be kept and the rest will be sent to an idle server). But now you may have a doubt, won't this be too slow? No, it won't be slow, firstly the constraint on the max keys will be small around 10,000 or maybe 5,000 if you want and then these servers themselves are pretty small and not so resource hungry. Hence once in a while a spike of 2ms is my tradeoff in this system.&lt;/p&gt;

&lt;p&gt;Now that I have the splitting mechanism explained let me confront one flaw my friend helped me realize. What about scaling down? When the keys decrease, then the active nodes should ideally merge together helping optimize server costs right? And that was the part I never thought while thinking about this design 😅. And its still hard for me to consider this since I'd need an orchestrator do this in an efficient way. And I'm guessing an orchestrator might not be a good solution if I want to scale this geographically, basically I'm not sure 😂&lt;/p&gt;

&lt;p&gt;Now comes the TTL part, so the problem statement also wants TTL and my design has a solution for that. I have some fraction of database machines dedicated just for TTL keys, they have an internal delete thread which deletes a key when their TTL hits. I could not have this on all databases since it would make them slower for a higher load due to concurrency issues. So when you put a key and then send a ttl request the dynamic bucket server moves your data from the normal database to on of the TTL database. And all operations for that key happen on the TTL server from that point of time onwards.&lt;/p&gt;

&lt;p&gt;But there's still a flaw here, if you're really understanding this then you might ask how does the load balancer know which dynamic bucket to pick? And my answer is health checks, so load balancers occasionally check for nodes healths and the total traffic on the node; so here a node's health is the range of key hashes it holds. The load balancer computes the hash of the key and then sends it to the dynamic bucket that holds the range. And if the key is in range of no bucket, it sends the key to an idle server. That server then becomes active and processes the request.&lt;/p&gt;

&lt;p&gt;There's a ton of holes (and I'm freaking out because of that 😂) but it's hard for me to cover all of them with such a low knowledge of system design, so we move on to the next one!&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Slack's Realtime Communication
&lt;/h3&gt;

&lt;p&gt;Yeah, it is a new problem statement added to the list. And it has no description... 🫣&lt;/p&gt;

&lt;p&gt;So one of my friends found slack's architecture on some &lt;a href="https://systemdesign.one/slack-architecture/" rel="noopener noreferrer"&gt;online blog&lt;/a&gt; and we understood the requirements.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The user can send real-time messages to another user and within a channel (group messaging)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The chat messages should be persisted and displayed in chronological order to keep the total order of messages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user can send media files such as pictures or short audio files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The chat service should display the online presence status of the users&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A chat message must be received by a user at most once to preserve message integrity&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yeah... too many requirements. And I came up to fill in some totally different requirements (along with some of these) 😇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwe1qncdhuw51001ew0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwe1qncdhuw51001ew0u.png" alt="Slack's Architecture" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So first things first, that Nginx logo on the left, it is a Media Server for WebRTC (couldn't find a better symbol 🫣). I got confused while explaining it before and I don't want the same to happen again 😂&lt;/p&gt;

&lt;p&gt;So the system is a pretty standard one, the clients connect to a load balancer and that load balancer redirects to any server it wants. Simple. But that is the for the normal server cluster. There is a second cluster called the socket server cluster and as its name suggests it handles web socket connections. A client connects to the socket server and establishes a web socket server directly with the socket server. Now both of them can talk to each other mostly without needing the load balancer (pardon the opposite happening in the design 😂).&lt;/p&gt;

&lt;p&gt;A socket server is used for showing real time events like a user is typing or a user is online/offline, or even for receiving a message, etc. A normal server is used for database updates like a user has sent a message (which then triggers the socket servers to send that message to the assigned user). An optimization here would be to use SSE instead of websockets since it would use lesser resources on the server side.&lt;/p&gt;

&lt;p&gt;Another thing this design covers is reactions to messages. Those reactions are written to a write-behind cache (basically it bulk writes into the database), mostly redis which is then updated later in the database.&lt;/p&gt;

&lt;p&gt;The last thing I covered is calls. The calls will happen using WebRTC. If it is a personal call then the traditional WebRTC works but in case of a group call I will have a separate Media Server which has just one job - receive frames from all the members of the group call and every tick send all the received frames to everyone. To understand why this is a better approach there's a ton of explainations on the internet, but in short it is the difference between a complete graph and a star graph (a graph seeming like a star, a central node connected to every other node, giving it n nodes and n - 1 edges).&lt;/p&gt;

&lt;h3&gt;
  
  
  Design a Load Balancer
&lt;/h3&gt;

&lt;p&gt;The final system design question I did this week was to &lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/load-balancer.md" rel="noopener noreferrer"&gt;design a load balancer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These were the core requirements:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ability to &lt;strong&gt;accept incoming TCP&lt;/strong&gt; connection and forward it to one of the configured backend server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ability to &lt;strong&gt;add&lt;/strong&gt; and &lt;strong&gt;remove&lt;/strong&gt; backend servers at will&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ability to &lt;strong&gt;monitor&lt;/strong&gt; healthy backend servers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ability to have a &lt;strong&gt;configurable&lt;/strong&gt; load balancing strategy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ability to &lt;strong&gt;measure&lt;/strong&gt; and monitor load balancer metrics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;should scale to &lt;strong&gt;millions&lt;/strong&gt; of concurrent TCP connections&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this was my design, a mix of HA and concurrency issues thrown at you 😂&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4t5sbihc9crc7fycx9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4t5sbihc9crc7fycx9b.png" alt="Load Balancer's Architecture" width="799" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the clients connect to the public IP of the system at which a load balancer sits. Now when I started designing a load balancer, I thought "Wait, isn't a load balancer a SPOF?" and I googled a bit and learned about the HA pair (High Availability pair), which is similar to the buddy system I thought of for my local cloud project. So as the name suggests, a HA pair has two machines both preferrably of equal specs. Now one is the active load balancer while the second is the passive one. When the DNS asks for the first time that who's IP is this the active load balancer responds while the passive one remains quiet. This is because both of them have a continuous exchange of heartbeats and if the passive load balancer keeps receiving the heartbeats from the active load balancer, it just does not do anything. But if the passive load balancer detects that the active load balancer has failed, it immediately starts to advertise its own ip address to the dns for the new coming requests. It also have a virtual IP in a lot of cases which helps with this, but the way how the switch happens is totally dependent on the implementation.&lt;/p&gt;

&lt;p&gt;Now coming to the servers, the servers will have an internal thread which will periodically ping the load balancer conveying its parameter. Say you want to use least request algorithm then the number will be the number of requests the server is currently handling and if you want to use lowest response time then it could be the average response time of that server, and for round robin you could send 1 bit dummy data or empty packets just for the load balancer to register you as "still living".&lt;/p&gt;

&lt;p&gt;Now we have some parts clear, let's dive into the load balancer itself. The load balancer has 2 threads in it. the first is the allocator thread which simply redirects the request to a server. Now since this is a thread, it will have a separate file of its own and hence if you want to change the algorithm from maybe LRU to round robin, just go ahead and compile the new binary right in that same directory. The only delay that comes is the OS's disk write time, which should not be more than 50ms even for the world's largest binary on such a powerful machine. Hence it is a one time delay but it allows dynamic configuration updates. Or maybe you could just write a new update to the passive HA machine and just switch roles, smooth transition 😂&lt;/p&gt;

&lt;p&gt;The second thread in the load balancer is the listener thread which simply listens for server's heartbeats and updates the shared memory. Oh I guess I introduced concurrency... 😁. This shared memory has a map and an array. The map's keys are the server IDs or the server MAC IDs. the values are the indices of that id in the array. The array contains the number that the servers give to the load balancer. Now comes the twist, the array has element wise locking while the map has a full lock. Why? Element wise locks are too expensive, but in this case they allow the listener thread and allocator thread to modify the shared memory at the same time. the map is only read and rarely modified hence keeping an element wise lock there would be mostly a waste of resources.&lt;/p&gt;

&lt;p&gt;Also, a small optimization we could have in this system is that the listener thread also stores a "next server" variable which it updates whenever a new server heartbeat is received. That is basically the server to next send the request to. If the algorithm is least requests, then "next server" is the server ID of the server which has the least requests currently, making it a constant time operation since it is happening at runtime. I could have used a better data structure but since I want the load balancer to be as fast as possible, it is better to use stale minimums for speed.&lt;/p&gt;

&lt;p&gt;So my load balancer's trade off is "not the ideal next server" for "high speed even at peak load".&lt;/p&gt;

&lt;h3&gt;
  
  
  Important stuff...
&lt;/h3&gt;

&lt;p&gt;I know this system has a ton of problems which I cannot see it yet. But if you like my blog and don't think of it as just another boring blog, you are free to destroy my design in the comments, I'd highly appreciate it!&lt;/p&gt;




&lt;h2&gt;
  
  
  The twisty idea
&lt;/h2&gt;

&lt;p&gt;Okay so I have got a freelance work from a company which had me make an app using flutter. And the app was very simple, I cannot share the details but think of it as a simple Inventory Mangement App.&lt;/p&gt;

&lt;p&gt;I just started building blindly this time since I knew Flutter, the requirements were clear, the app had to be totally offline and serverless.&lt;/p&gt;

&lt;p&gt;But as I built I faced a question, a question so good I wish I did not think of it 😂&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;The app was working perfectly! But now think of this, if a user has a phone and a desktop and wants to open the app on both, then every time he/she wants to add a new item or delete an item he/she will have to do it on both the devices right? So to solve that issue I proposed a new idea... to allow offline sync.&lt;/p&gt;

&lt;p&gt;I wish I hadn't proposed the idea 😓... but then I would have missed on a lot of new things I learnt in the 2 weeks I explored this 😄&lt;/p&gt;

&lt;h3&gt;
  
  
  Answer?
&lt;/h3&gt;

&lt;p&gt;So if you're going to answer &lt;strong&gt;WebRTC&lt;/strong&gt;, that is not the complete answer my friend. I also thought of the exact same thing, "let's use WebRTC for message transfer!" but that soon ran into a problem...&lt;/p&gt;

&lt;p&gt;To understand the why, let's look at how WebRTC works. So basically WebRTC has 3 types of servers (techincally 4 if we consider a fallback server but mostly 3). The first is the signaling server. To even establish a connection, the devices need to exchange SDP Offer and SDP Answer packets. After that's done, both the devices ping a STUN server (basically an echo server which returns the public ip of the sender) and then via the signaling server they exchange their public ips. So now device A knows device B's public ip and B knows A's public ip.&lt;/p&gt;

&lt;p&gt;Now comes the amazing part, normal devices are under NATs and a lot of other networking stuff making them totally hidden to external devices. Hence communication can be established only if a device from within a NAT requests to communicate to a device outside. And WebRTC does that exactly, device A or B whichever is faster at this point tries to communicate to the other device. So now say A arrived at this step first and it wants to communicate to B's public ip. A's NAT has no problem and registers that A talked to B via this public ip and this port even though B's NAT does not allow A's request in the NAT of A has a "hole" in it. Now the other device, device B does that same thing, it sends a request to A's public ip. Again B's NAT registers that B talked to A via this public ip and this port but this time B's request is able to reach A since A's NAT was expecting B to talk to A. This is called "punching a hole" in the NAT of both devices. And this is what allows A and B to have a direct P2P connection.&lt;/p&gt;

&lt;p&gt;Now let's understand why we have a problem, firstly the app should ideally be working offline hence the signaling server is.... just not an option 😅&lt;/p&gt;

&lt;p&gt;So let's look at some good options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use the internet!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scan the LAN...&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a more time consuming method...&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So option 1 is the default one, yeah even though the app is an oflline first app we will use the internet just for this bit. So in this option, the app will be doing WebRTC but using BitTorrent. Yep, something totally unrelated is coming in. So the SDP Offer and SDP Answer will be on BitTorrent. Both the devices will be scanning the BitTorrent network for updates on a shared agreed key and the SDP Offer will also have a timestamp, that is when the devices will connect this ensures no polling and direct connection when possible. Now you should ideally ask, if we're using BitTorrent why use WebRTC? Because BitTorrent only allows some small amounts of data to be hosted on the network for free, and if our sync data is small enough we could optimize but it generally should not be the case hence WebRTC 😁&lt;/p&gt;

&lt;p&gt;But suppose the devices are in a basement, we certainly can't get internet connectivity there right? So let's check if the devices are in the same LAN and if we're lucky we don't have to fallback to the last manual method. We could ideally use something like WifiDirect or Bluetooth for this but I'll figure that out during implementation.&lt;/p&gt;

&lt;p&gt;The last option is the weirdest, I couldn't think of a better way 😂 so I came up to use the mule method 🫠 the oldest method in computer science to transport data across a distance.&lt;/p&gt;

&lt;p&gt;Now picture this, device A is in a basement and device B is also in a basement. Neither of them can connect to any router or any other electronic device which could help us connect with the internet since even WebRTC needs some kind of path from A to B via routers and switches.&lt;/p&gt;

&lt;p&gt;So what I came up with is (after a huuuuge chat with Gemini 😂) the &lt;a href="https://en.wikipedia.org/wiki/Data_mule" rel="noopener noreferrer"&gt;mule method&lt;/a&gt;. When the internet did not exist and even today at some places, this method is the best for data transfer across disconnected devices.&lt;/p&gt;

&lt;p&gt;This is the plan, device A is in a basement and there will be workers which will update it. So now if those workers have the same app in their phones (which needs to be opened atleast once since the last reboot) and if I setup a geofence trigger in those phones and then whenever that phone comes near device A it will automatically run the merge script and store it in itself. Let's call this device A1 which is the device with the worker. Now device A1 has the updated data of A similarly there will be a device B1 which will have the updated data of device B now when these workers leave the basement and get internet connectivity their devices will use WebRTC to establish the connection and complete the exchange. This can be done by sending the user a notification which will open the app for some seconds and the app on both devices A1 and B1 will complete their data merges and both will have the updated tables (those tables are deterministic because of HLCs).&lt;/p&gt;

&lt;p&gt;And then when A1 goes back to the basement with A it will sync data with A using geofencing and similarly B1 will sync data with B using geofencing trigger. This will help us use the concept of data mule in an offline environment. I am planning to create a C script for this and then using flutter, I'd execute this c script and do the magic.&lt;/p&gt;

&lt;p&gt;There are a ton of pitfalls waiting for me, they'll pop up one by one as I implement this 😂&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Micellaneous Stuff"
&lt;/h2&gt;

&lt;p&gt;So I am a development oriented guy, but for placement I give contests on leetcode, codechef and codeforces. And recently my leetcode and codechef ratings have started to go up slowly, a bit exciting and shocking for me 😂&lt;/p&gt;

&lt;p&gt;Placements require me to reach 1800 in leetcode and 2 star on codechef 😓. That's pretty... hard 🙂. But somehow I am a 2 star on codechef and around 1742 on leetcode after a long long time of just wishing I also have good ratings it is finally happening 😂 But I'm still afraid of DP 🫣&lt;/p&gt;

&lt;p&gt;Also, I found a github repository I think is worth sharing, it is open source and is actually a great thing for someone who is interested in low level stuff. They are all from the same person 😂&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Jay-1409/pragmaticDB" rel="noopener noreferrer"&gt;Pragmatic DB&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Jay-1409/InfraNotify" rel="noopener noreferrer"&gt;InfraNotify&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Jay-1409/oxygn" rel="noopener noreferrer"&gt;Oxygen&lt;/a&gt; (Yeah that's really its name 😂)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These repositories have a good goal set but some things are still waiting for a fix, give it a try I bet you'll want to contribute atleast once 😅&lt;/p&gt;




&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;That's it for today I guess... I mean I hope to stay consistent and more focused, but stay tuned! Thanks a lot for reading!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fc.tenor.com%2FfL3b7XFOryAAAAAC%2Ftenor.gif%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fc.tenor.com%2FfL3b7XFOryAAAAAC%2Ftenor.gif%2520align%3D" alt="Skeleton Thank you GIF" width="498" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Credits: &lt;a href="https://tenor.com/view/thank-you-thanks-a-lot-tysm-blush-flustered-gif-8988582244156092192" rel="noopener noreferrer"&gt;Tenor&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you have a bit more of time and like to support me, I also write on other two platforms and would appreciate if you could give just a view to those blogs too 😅&lt;/p&gt;

&lt;p&gt;Medium: &lt;a href="https://medium.com/@meetgandhi13062005/from-slack-clones-to-data-mules-my-descent-into-system-design-madness-84cb04252ffc" rel="noopener noreferrer"&gt;https://medium.com/@meetgandhi13062005/from-slack-clones-to-data-mules-my-descent-into-system-design-madness-84cb04252ffc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hashnode: &lt;a href="https://keep-alives.hashnode.dev/from-slack-clones-to-data-mules-my-descent-into-system-design-madness" rel="noopener noreferrer"&gt;https://keep-alives.hashnode.dev/from-slack-clones-to-data-mules-my-descent-into-system-design-madness&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Day the machines talked and Bloom Filters bloomed!</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Sat, 16 May 2026 10:34:45 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/day-the-machines-talked-and-bloom-filters-bloomed-31g2</link>
      <guid>https://dev.to/geniusmind9999/day-the-machines-talked-and-bloom-filters-bloomed-31g2</guid>
      <description>&lt;p&gt;Hello reader! As you know I am building CodeArena and it is a decentralized system. So this is the content I will be covering in today's blog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;CodeArena Progress - The machines can now elect a leader and the system is capable of repairing itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;System Design Question - Peer discussion on today's system design problem helped us come up with an amazing solution which was just a thoughtful combination our solutions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next Plans - What I will be doing next in CodeArena and in System Design along with some in parallel "mini" tasks as sprinkles on ice cream 😂.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  CodeArena Progress
&lt;/h2&gt;

&lt;p&gt;So last time I had architected the system and this time I have implemented a part of it. The whole system is too huge and complex (yeah I realize it more and more as I implement it 😂) and hence implementing every feature even for a single node is not less than a nightmare 🫠.&lt;/p&gt;

&lt;p&gt;But nevertheless I wrote the C code for an empty node (an incomplete empty node 😂). This node has two threads one is a sender and the second is a receiver. When the node starts, it creates two sockets, one for listening heartbeats and one for sending heartbeats. Both of these threads have a shared variable that holds a &lt;code&gt;struct sockaddr_in&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;The sender first checks if the shared variable does have an address or not (yeah, I used a bool to check for that, that is another shared variable) and if it does not have any value the sender will send its own heartbeats to the network as broadcast.&lt;/p&gt;

&lt;p&gt;Meanwhile the receiver hears for any existing monitor signals. Now suppose the system is just starting so this thread won't hear any monitors. So the thread tries 5 times to hear the monitor heartbeats (the socket has the &lt;code&gt;SO_RCVTIMEO&lt;/code&gt; option enabled hence it times out every 500 milliseconds when it does not get data). So when it does not hear the monitor for 5 consecutive heartbeats, it starts an election with all other empty nodes.&lt;/p&gt;

&lt;p&gt;The receiver thread then calls another function which performs the consensus. The consensus is bascially a UDP voting mechanism and these are the details of how I built it. This new function creates two new threads, lets call them s2 and r2 since I cannot use the name sender and receiver again 😂. so now s2 sends 3 &lt;code&gt;consensusStart&lt;/code&gt; packets and r2 listens for 3 &lt;code&gt;consensusStart&lt;/code&gt; packets sent by itself (every node has a unique UID which I get from the kernel's entropy pool). So once s2 sends 3 such packets it becomes the receiver and starts collecting votes from other nodes. And once r2 gets 3 packets it sends a vote packet thrice in the network. the vote packet contains a random number.&lt;/p&gt;

&lt;p&gt;Every node puts its own random number in the start packet. now the r2 threads collect these and pick the highest received random number (the random number can be the number its own s2 sent). Now s2 listens for these voted numbers and figures the 50% + 1 voted number. If the voted number is its own generated number this node becomes the new monitor and otherwise everything continues like nothing happened. r2 and s2 exit normally.&lt;/p&gt;

&lt;p&gt;Now suppose a node starts off and there is a monitor already present, then in this case the node first sends a broadcast using its sender thread as usual but this time the monitor replies it using broadcast saying "Yeah, I am the elected monitor and you can send your heartbeats to me". Now this message is not listened by the sender, this is a very decoupled system hence difficult to understand (I had to refer my code twice to write this down in simple words 😅, but 0% AI for sure!).&lt;/p&gt;

&lt;p&gt;This message from the monitor is heard by the receiver thread which updates the shared &lt;code&gt;struct sockaddr_in&lt;/code&gt; variable and puts in the monitor address. Now the sender thread is doing its job by sending "Hello, Anyone there?" signals but as soon as the receiver updates the variable the sender thread would send a unicast heartbeat to the monitor from the next time.&lt;/p&gt;

&lt;p&gt;The monitor also sends out heartbeats every 500 milliseconds so that the nodes know no need to conduct elections right now.&lt;/p&gt;

&lt;p&gt;This means that if I allow the nodes to settle (I did test this for 4 pcs and it works) and then terminate the program on the monitor, the other nodes pick a new monitor quickly stabilizing the system under 5 seconds.&lt;/p&gt;

&lt;p&gt;So this was everything I built till now, but I am working on more next which come up in the later section.&lt;/p&gt;




&lt;h2&gt;
  
  
  The System Design Question
&lt;/h2&gt;

&lt;p&gt;So today's question (more precisely, yesterday's question 😅) was &lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/online-offline-indicator.md#design-an-online-offline-indicator" rel="noopener noreferrer"&gt;this&lt;/a&gt;. The question involved creating an Online Offline Indicator.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Core Requirements:&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;should update online status of a user within &lt;strong&gt;10 seconds&lt;/strong&gt; of user coming online&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;can be &lt;strong&gt;lenient&lt;/strong&gt; in marking a user offline&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;should scale for &lt;strong&gt;5 million&lt;/strong&gt; active users at any given moment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a user should see accurate status of any other user, &lt;strong&gt;eventually&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Think of Discord, it shows you whether a user is online or offline using that small green/red dot. This is nearly the same question.&lt;/p&gt;

&lt;p&gt;So this was my approach:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuu9zib7if4tda6mxhpu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuu9zib7if4tda6mxhpu8.png" alt="Built upon the previous design, 7 continents with a server each, every continent server has its region servers. This time the servers won't have redis as cache but the Bloom Filters as a cache." width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This design is very blur since Dev does not allow svgs, a better image can be found on Hashnode. Checkout the hasnode blog to have a better view, link at the end.&lt;/p&gt;

&lt;p&gt;Okay, big design, not so readable, typical me 😂&lt;/p&gt;

&lt;p&gt;So this design is built on my previous design as you can see in the left corner. In this design too every continent has a single server and every such continent server has multiple region servers. Now instead of using redis as a cache, these servers use bloom filters as cache. The good thing about bloom filters is they have O(1) reads, updates and consume a lot less memory. Not exactly O(1), it is O(k) which is the number of hash functions the filter uses, so in this case it should be around O(2) or O(3) which is O(1) I assume 😅&lt;/p&gt;

&lt;p&gt;So every read goes into the local bloom filter then to the region database and then to the continent bloom filter then to the actual continent database and finally to the intra continental database. Read is trivial there might be very few cases where in the request travels so much and even if it happens it would happen exactly once since the system will sync information according to the frequency of connection between two users. If a american user has an australian friend the servers would be updated in both places.&lt;/p&gt;

&lt;p&gt;And for the writes, the user's machine periodically (about 1 minute) pings the region server that it is still online. the region server updates the bloom filter and continent server if the user was previously offline. and if the update does not come through the regional server marks that user as offline and removes them from the bloom filter and sends the update to the continent database.&lt;/p&gt;

&lt;p&gt;Now there was a flaw in this which I got to know when I saw the design of my other friend. The flaw was that I was using a persistent database for something which does not need persistence. It would be okay if your friend is shown offline for a minute or 30 seconds while you are chatting with them but eventually their correct status should be revealed.&lt;/p&gt;

&lt;p&gt;My friend (who actually knows more system design than me, not kidding) had used an amazing technique and scaled the system using only redis but the concept was just mind blowing!&lt;/p&gt;

&lt;p&gt;He used distributed caching, a built in feature of redis. The architecture inside redis is Master Slave architecture wherein a master has n number of slaves and those slaves are read replicas. and there is a central server which handles the client requests. The data is divided into buckets and kept in the redis. Each bucket has a master which is connected n number of slaves. Now at any time a master can fail hence to ensure the system does not fail redis allows a slave to be controlled by any other master if its master dies.&lt;/p&gt;

&lt;p&gt;And I genuinely find this design genius, like suppose if the central server was a continent server in my design and the regional servers are the masters. And the slaves are the local servers. Think of the speed of the system if the redis instances were replaced with bloom filters! Though this system I just described more polishing and I agree it has a lot of problems you could potentially use to destroy the system, but it is overall an amazing system.&lt;/p&gt;

&lt;p&gt;My friend got his inspiration from this &lt;a href="https://medium.com/@123williams93/distributed-caching-in-redis-8ff882bf79ac" rel="noopener noreferrer"&gt;blog&lt;/a&gt;. And he is a really smart guy, you should really check out his &lt;a href="https://www.linkedin.com/in/drumil-bhati/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next Plans
&lt;/h2&gt;

&lt;p&gt;So next I am going to take a deep dive into linux containers and linux rootless containers (Yeah both are different, totally different 😓)&lt;/p&gt;

&lt;p&gt;And as far as System Design is concerned, we are going to approach this &lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/airline-checkin.md" rel="noopener noreferrer"&gt;question&lt;/a&gt;, and if you're someone who is better in system design, we'd like to genuinely learn from you and even if you're just starting out we're with you since we are also basically in the "just starting out" phase 😄&lt;/p&gt;

&lt;h3&gt;
  
  
  The parallel processing
&lt;/h3&gt;

&lt;p&gt;So currently I got an amazing freelance work from a to-be start-up. And the sad part is it is nothing around systems, but the work involves developing mobile and desktop cross platform app along with website. And also having offline sync, yeah no internet is allowed. The app should not use the internet even if it is available. Now I cannot share all the details but this is as far as I could go 😁&lt;/p&gt;

&lt;p&gt;The other smaller "sprinkles" are that I am going to continue my freelance work soon at another company (yeah I had to pause due to my exams and later some problem from the organization).&lt;/p&gt;

&lt;p&gt;Along with that I am planning to explore the Linux repository and looking forward to getting my name on that mailing list (I hope so! 😅) and also refreshing my compiler design concepts to later explore LLVM (around August or September, as soon I get comfortable with looking at linux's repository 😂).&lt;/p&gt;




&lt;h2&gt;
  
  
  Thanks and goodbye!
&lt;/h2&gt;

&lt;p&gt;Thanks a lot for reading this till here! Will keep the blogs coming at a better pace, but till then &lt;strong&gt;Sayonara&lt;/strong&gt;!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztj8kqk0a25bu0noydk8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztj8kqk0a25bu0noydk8.gif" alt="Bye Bye GIF" width="355" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GIF Credits: &lt;a href="https://tenor.com/pptzyr1WqHS.gif" rel="noopener noreferrer"&gt;https://tenor.com/pptzyr1WqHS.gif&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've read till here and if you just a bit more time, I write on other platforms as well and I would appreciate if you could give my blog a view on those platforms 😅&lt;/p&gt;

&lt;p&gt;Hashnode: &lt;a href="https://keep-alives.hashnode.dev/day-the-machines-talked-and-bloom-filters-bloomed" rel="noopener noreferrer"&gt;https://keep-alives.hashnode.dev/day-the-machines-talked-and-bloom-filters-bloomed&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Medium: &lt;a href="https://medium.com/@meetgandhi13062005/day-the-machines-talked-and-bloom-filters-bloomed-4cd28cd4fcda" rel="noopener noreferrer"&gt;https://medium.com/@meetgandhi13062005/day-the-machines-talked-and-bloom-filters-bloomed-4cd28cd4fcda&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>devjournal</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Finally architected my local cloud!</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Sat, 09 May 2026 13:08:14 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/finally-architected-my-local-cloud-2oh2</link>
      <guid>https://dev.to/geniusmind9999/finally-architected-my-local-cloud-2oh2</guid>
      <description>&lt;p&gt;If you are a new reader, here's the context. I along with 2 other friends am planning to create &lt;strong&gt;CodeArena&lt;/strong&gt; a platform built for students and professors in mind aimed to increase students' learning while decreasing the workload on the professor to manage them.&lt;/p&gt;

&lt;p&gt;Yeah, huge expectations but we are still in the planning phase. Can't wait to actually see it getting used by students and professors!&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;So as a student with interest in OS kernels and compilers, I came up with a HUGE design. And believe me, I am in love with this design 😂&lt;/p&gt;

&lt;p&gt;So let's get to the fun part, the system is a client server architecture which is trivial (yeah, see the server architecture and you'll find this one trivial 😂). The server internally consists of another architecture made of three layers or three types of nodes.&lt;/p&gt;

&lt;p&gt;So some clarifications before we actually dive in, the first thing is that we're using the lab PCs of our university so the system we install there should be considerate of how much load the machine is currently in and how much it should load the machine. And plus the machines can shut down anytime so the system needs to be elastic enough to handle that.&lt;/p&gt;

&lt;p&gt;So the first type of node is the Gateway node and that will be a personal computer and it will be the only node in the system to be singular. I mean in this system there can only ever be a single Gateway node, strictly.&lt;/p&gt;

&lt;p&gt;The second node is an Orchestrator, this node too has 2 types in it a monitoring orchestrator (monitor for short) and an assigning orchestrator (assigner for short) each of which handles different types of work.&lt;/p&gt;

&lt;p&gt;The third type of node is the Worker node which basically runs the code given by the client in a linux container (surprise! I am not using Docker 😂).&lt;/p&gt;

&lt;p&gt;The last node is the Empty node which actually does nothing, it is just in the system in case the load increases or some machines go down.&lt;/p&gt;

&lt;p&gt;So this was the overview but here is the description of each...&lt;/p&gt;




&lt;h3&gt;
  
  
  Gateway
&lt;/h3&gt;

&lt;p&gt;This node is a personal computer (mostly my pc) on which some parameters are set. These parameters include (but not limited to) number of usable pcs in the lab with their IP addresses, the bare minimum number of all types of nodes for the system to function.&lt;/p&gt;

&lt;p&gt;The client sends a request to this Gateway which handles request using a high level language like JS or Go and then communicates with the internal system using TCP.&lt;/p&gt;

&lt;p&gt;Now the Gateway is a Single Point of Failure if you pay close attention. To tackle this, an Orchestrator node will make use of Gratuitous ARP to make this an active / passive High Availability setup instead of a Single Point of Failure!&lt;/p&gt;




&lt;h3&gt;
  
  
  Orchestrator
&lt;/h3&gt;

&lt;p&gt;This node is just another lab computer. There are two types of orchestrators as I mentioned previously, lets look at both one by one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitoring Orchestrator:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This orchestrator will collect heartbeats from all the other nodes in the network (yes even other monitoring orchestrators) and keep track of which nodes are alive and how much work they have.&lt;/p&gt;

&lt;p&gt;And this node will also periodically send out heartbeats which contain all the information it has about the worker nodes and their workloads.&lt;/p&gt;

&lt;p&gt;The monitoring orchestrators in the network also use the Gossip protocol to keep each one updated about what is going on in the system, because one node will never broadcast what it did that simply makes the system inefficient so instead the monitoring nodes periodically sync their knowledge among themselves making sure even new monitoring orchestrators have the same information.&lt;/p&gt;

&lt;p&gt;When the Gateway gets a new client it asks one of these Monitors to lead it to the least loaded Assigner in the network who can then carry out the remaining flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assigning Orchestrator:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This orchestrator will get new client requests from the Gateway (lead by a Monitor) and it will use its knowledge of load on Worker nodes given by the periodic heartbeats of Monitors and assign this task to a Worker node.&lt;/p&gt;

&lt;p&gt;The Worker node can either accept the task or can reject it, in the latter case the Assigner simply tries with a different Worker node.&lt;/p&gt;

&lt;p&gt;The Worker node will also stream chunks of 1500 byte output it gets from the container running the code which this orchestrator will stream to the gateway and using websockets it would be streamed to the client. And for inputs, the client will send data packets to the gateway (not exactly streaming since it would be sent once the client presses enter) which will then send this packet to the Assigner and to the container.&lt;/p&gt;

&lt;p&gt;The Assigner is a crucial failure point in this system currently so to make it a less probable failure I introduced a Buddy system where in the number of Assigners in the system will always be even, every Assigner has a Buddy Assigner. These two "buddies" will gossip their work to each other and in case one fails the other will take over until a Monitor does not assign a new Buddy Assigner to this node.&lt;/p&gt;

&lt;p&gt;This orchestrator will also check for Monitor's heartbeats and in case it does not get 5 consecutive heartbeats the Assigners elect a new Monitor and along with that its Buddy will also become a Monitor, so in place of one Monitor two new Monitors will be created (A true Hydra System 😂).&lt;/p&gt;




&lt;h3&gt;
  
  
  Worker
&lt;/h3&gt;

&lt;p&gt;This node will also be a process on a lab computer, but the special thing here is multiple Workers will co-exist in one machine. The number of workers in a machine is equal to the number of cores that machine has, this will allow the system to take advantage of parallelism at the hardware level.&lt;/p&gt;

&lt;p&gt;The Worker node has 3 threads, a &lt;strong&gt;communicator&lt;/strong&gt; thread, a &lt;strong&gt;runner&lt;/strong&gt; thread and a &lt;strong&gt;heartbeat&lt;/strong&gt; thread. The details of each are below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Communicator Thread:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The communicator thread facilitates communication between the Orchestrators and the Worker. It gets a request from the Orchestrator and if the machine's PSI is below the defined boundary it creates a new &lt;strong&gt;Runner&lt;/strong&gt; thread and hands over the code to that thread.&lt;/p&gt;

&lt;p&gt;It also kills a Runner thread in case of container failure, abrupt exit of the thread or if executing the code is complete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runner Thread:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The runner thread creates a new rootless container using Linux namespaces. This would allow our system to be able to run without the need of having sudo access on the machine.&lt;/p&gt;

&lt;p&gt;This thread also streams output received from the program running in the container to the Orchestrator in blocks of 1500 bytes. And it also takes input from the Orchestrator (the input comes from the client to the Gateway then to the Orchestrator) and provides this input to the program running inside the container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heartbeat Thread:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The heartbeat thread sends periodic pings to the controller thread of the process ensuring that the thread is not dead yet. It does this using &lt;code&gt;Unix Domain Sockets&lt;/code&gt; or &lt;code&gt;UDS&lt;/code&gt; for short.&lt;/p&gt;

&lt;p&gt;This thread then sends periodic heartbeats to a Monitor making sure the Worker process is actually alive.&lt;/p&gt;




&lt;h3&gt;
  
  
  Empty Node
&lt;/h3&gt;

&lt;p&gt;This node is a lab computer which is not either of the above mentioned nodes. This node is used when a node in the system fails or when the load on the system increases.&lt;/p&gt;

&lt;p&gt;Its only job is to ping a Monitor and give heartbeats at specific time intervals.&lt;/p&gt;




&lt;h2&gt;
  
  
  New things I am planning to learn
&lt;/h2&gt;

&lt;p&gt;So some of the things I am excited for are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Linux Namespaces, Cgroups and a lot more container level stuff. Basically everything that Docker abstracted away&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing distributed algorithms like RAFT for leader selection&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing &lt;code&gt;Gratuitous ARP&lt;/code&gt; so that a failing gateway can be quickly replaced.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And I am planning to start writing the C code for each of these nodes just after finishing my blog. Yeah and just like always without AI writing a single line of code but AI helping me find Linux docs.&lt;/p&gt;




&lt;h2&gt;
  
  
  What else I did
&lt;/h2&gt;

&lt;p&gt;So this is not the only thing I did in this week after my last blog. I also practiced a bit of System Design. So me and my peers were trying to design a system (HLD since this is the first time we're doing something like this, the next time we're planning to have LLD as well) for a Blogging Platform.&lt;/p&gt;

&lt;p&gt;So this was the problem statement&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Design a simple multi-user publishing/blogging platform, allowing writers to publish and manage the blogs under their personal publication and readers to read them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the requirements:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Core Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;writers should be able to &lt;strong&gt;publish&lt;/strong&gt; blog under their personal publication&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;readers should be able to &lt;strong&gt;read&lt;/strong&gt; the blog&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a user can be both - a reader as well as a writer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;author of the blog should be able to &lt;strong&gt;delete&lt;/strong&gt; the blog&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;blog may &lt;strong&gt;contain images&lt;/strong&gt;, but will not contain any video&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;time to access the blog should be &lt;strong&gt;as low as possible&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;we have to render "&lt;strong&gt;number of blogs&lt;/strong&gt;" written by every user on his/her profile&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;users should be able to &lt;strong&gt;search&lt;/strong&gt; for a particular blog&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the platform should be scaled for &lt;strong&gt;5 million&lt;/strong&gt; daily active readers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the platform should be scaled for &lt;strong&gt;10,000&lt;/strong&gt; daily active writers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;And my system was well a bit too huge. It was decentralized 😉&lt;/p&gt;

&lt;p&gt;So what I came up with was a childish excalidraw diagram of the system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foco7fcnyxvx3a6tx6mdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foco7fcnyxvx3a6tx6mdc.png" alt="An excalidraw diagram which consists of a box with 7 concentric circles. Inner circle is green and outer is red. there are three each side and the 7th in the bottom center. The 7th circle also contains are rectangle around it with 2 smaller concentric circles labelled DB 7.1 and DB 7.2. Above this rectangle is a necklace is like structure with seven circles connected via a loop like line. One of these circies, specifically the bottom one, has multiple more smaller circles connected to it, arrows drawn from the big circle to the smaller ones." width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So don't judge me, I made it in 4 hours while still in sleep 😅&lt;/p&gt;

&lt;p&gt;So the 7 concentric circles here are the servers for each continent (yeah I included Antarctica, don't judge me now!) and the red circle around them is the independent database for each server. My system is decentralized and the database is distributed.&lt;/p&gt;

&lt;p&gt;So this system has two levels of servers, level 1 servers are the continent level servers, very powerful servers and can operate at high speeds. The level 2 servers are servers in countries. A country could have more than one server if needed.&lt;/p&gt;

&lt;p&gt;So when a writer wants to create their blog they ping (wrong word but you have no option 😁) their nearest level 2 server probably in their country. This level 2 server then updates the database in the level 1 server of the continent. Now the level 1 server will acknowledge and the writer's blog is published. And now eventually the level 1 server updates the level 2 servers of &lt;strong&gt;its continent only&lt;/strong&gt;. And the level 1 server propogates this information in batches (there's also timeouts so if a writer did publish a blog and no new writer publishes for say 2 hours the data even if there's just one blog entry will travel across these servers) to the servers of the other continents so that data stays eventually fresh in the system.&lt;/p&gt;

&lt;p&gt;Now suppose a reader requests a blog from their nearest level 2 server, now if the blog is in the database of the level 2 server (it also has a cache but it is well understood I suppose, independent cache to be more precise not shared cache). it will be served as quickly as possible but if the blog is not there, the level 2 server asks the level 1 server for the blog. And the response of the level 1 server is what reaches the client and also gets stored in the level 2 server.&lt;/p&gt;

&lt;p&gt;The level 1 servers do sync their data (which is timestamped to avoid things like lost updates) occasionally, say every 24 hours, after a set checkpoint to avoid the system from becoming a bandwidth hungry monster. This syncing is different from the blog level syncing I told about a second ago with the assumed 2 hour delay. This data exchange makes sure any new data since the previous exchange is aggregated to maintain the eventual consistency.&lt;/p&gt;

&lt;p&gt;This system prioritizes Availabilty over Consistency so even if a person from europe has published their blog a minute ago, their american friend might or might not see it for another 2 hours (that's what we assumed before). And that is okay since a blogging platform should be available even if the blogs are eventually updated. After all as a great person once told me,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Systems is always a trade off, you decide which one you want!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But in case of a partition inside the level 2 servers, the system chooses consistency. So if a level 2 server crashes and reboots it might be possible it missed some data, so it will get new data from the level 1 server after the last synced timestamp. Here the data transferred would be respective to the region the level 2 server is in. If this is a level 2 server in China, it won't get data of Russian writers until it requests later on. It might also get data of more read blogs but not everything at once.&lt;/p&gt;

&lt;p&gt;So yeah this was my design of this system. It is complex, it is incomplete and it is full of flaws but it is my original system hence whatever flaw you do point out, I will simply add a new patch to my system without having to switch over to something else (except when the problem is a part of the architecture, in that case I'll enjoy learning something from you!).&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Next I'm gonna write the code for all the types of nodes of my local cloud and then I'll also create a new system for the next system design question. This time with LLD too.&lt;/p&gt;

&lt;p&gt;So not committing fully, but by the next blog I will be ready with the node codes and probably a better system design of the &lt;a href="https://github.com/arpitbbhayani/system-design-questions/blob/master/online-offline-indicator.md" rel="noopener noreferrer"&gt;next problem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks a lot for reading, see you around Amigos!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4w0hjneqvmcwx1tjbeo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4w0hjneqvmcwx1tjbeo.gif" alt="BYEEEEEEEEE GIF from Tenor" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GIF from &lt;a href="https://giphy.com/gifs/willsmithsbucketlist-will-smith-facebook-watch-smiths-bucket-list-13QpHNxXQDqh42TPEW" rel="noopener noreferrer"&gt;Tenor&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I also write on other two platforms, so if you have a bit more time I would appreciate a comment or view on either or both of these platforms!&lt;/p&gt;

&lt;p&gt;Hashnode: &lt;a href="https://keep-alives.hashnode.dev/finally-architected-my-local-cloud" rel="noopener noreferrer"&gt;https://keep-alives.hashnode.dev/finally-architected-my-local-cloud&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Medium: &lt;a href="https://medium.com/@meetgandhi13062005/finally-architected-my-local-cloud-45926607b336" rel="noopener noreferrer"&gt;https://medium.com/@meetgandhi13062005/finally-architected-my-local-cloud-45926607b336&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>The Heartbeat Frame</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Sat, 02 May 2026 16:46:55 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/the-heartbeat-frame-4oej</link>
      <guid>https://dev.to/geniusmind9999/the-heartbeat-frame-4oej</guid>
      <description>&lt;p&gt;Long time no see… Again! I just survived my exams a day ago and I could not help but jump straight to writing this blog! Since this blog does not have something I have done already, this is a Heartbeat frame similar to a WebSocket connection 😁&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvobd6br6d2daw1snwhjr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvobd6br6d2daw1snwhjr.gif" alt="Jerry from Tom and Jerry holding his beating heart" width="200" height="200"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;So I was a teaching assistant in the Object Oriented Programming course at my university this semester. And the good news is that I am going to be the teaching assistant for the Operating Systems course next semester too! And for that me and my other 2 friends (who are also teaching assistants next semester with me) have decided to create a new platform for students to code in. Now I know what you might be thinking,&lt;/p&gt;

&lt;p&gt;“Oh hey meet, there are tons of such platforms that have a lot of different capabilities, I don’t see a good motive here!”&lt;/p&gt;

&lt;p&gt;Yeah that thought crossed my mind… and that is something we are still working on 🫠. So basically this is a project we are doing for learning something new. The three of us have different interests, I have an interest in systems, one of my friend has an interest in UI and ML and the third one has an interest in backend and also systems (similar but not the same). So we have decided to make the building process modular too.&lt;/p&gt;

&lt;p&gt;So here’s the (simple?) plan, We will build a platform with various roles like professor, student, teaching assistant, admin and maybe developer. Now each role can do different things.&lt;/p&gt;

&lt;p&gt;The Professor can create and monitor contests given by students and decide the way to derive the results. The professor can also change a students marks (yeah we have to keep this after a looong discussion 😂)&lt;/p&gt;

&lt;p&gt;The student can see their contests and also give them at the time set by the professor. There is a feature where the students can create contests for themselves too (not graded definitely 😂). And multiple students can join in and practice. The questions will be from a common question bank, it could be from the already taken contests or something new that the professor or teaching assistant provides.&lt;/p&gt;

&lt;p&gt;The admin… is well the ADMIN! Like they can literally change roles, manipulate contests and blah blah blah, you know what an admin does! Nothing unique here 😇&lt;/p&gt;

&lt;p&gt;And finally a developer can act as any of the roles and test the platform. This user won’t be visible to anyone except other developers. Yeah we have to “safely” test the platform without having to create 50 students and 10 professors who do not exist 😂&lt;/p&gt;

&lt;p&gt;Now comes the best part, I will be creating a local cluster of computers for this! Yeah, we are planning to run the student's code in a "custom" container (or docker if the "custom" container does not work) which will be created using linux namespaces (seems very exciting to me! 😁). And there will be a cluster of computers (most probably our university's computer lab PCs 😁) which will be connected to 3 laptops. Now this will be a "decentralized" system, atleast I aim to make it so. The three laptops will be masters and the lab PCs will be slaves, making it a master-slave (leader-follower to be more technical 😂) architecture. So there will be two kinds of slaves, one that receives a request from a client (not more than 2 most probably 😅) and the other which runs code in these containers.&lt;/p&gt;

&lt;p&gt;So I know what you’re thinking… Most probably 😅&lt;/p&gt;

&lt;p&gt;“Why introduce so much complexity when you have options like Kuberneters and Docker which are battle tested?”&lt;/p&gt;

&lt;p&gt;The simple and the only answer is, just for FUN 😂! Yeah I have literally no other reason! Why should I use Kubernetes and Docker when I build my own mini-cloud against it 😁? After all knowing what Docker does is equally important compared with using it in real production systems. But any custom solution cannot beat an open source “bulletproof” system like Docker and Kubernetes. Atleast not mine which is made in 1–2 months 😉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8497c1jgqnwyc8zbq8i.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8497c1jgqnwyc8zbq8i.gif" alt="A scene from Fast and Furious where the driver says " width="480" height="200"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;And along with this project I am planning to get a deep look into the linux kernel in this vacation and maybe even contribute a bit there! Exciting but still imaginary 😂&lt;/p&gt;

&lt;p&gt;And sometimes when I will get bored which I know I will, I will refresh my Compiler Design course I had taken this time (which I could not pay enough attention to 😅) from NPTEL. Cause after I am done with the Compiler Design course I want to explore LLVM as well. Knowing that I am facing a hydra, I might as well bring a stone sword to emotionally support me 😂.&lt;/p&gt;

&lt;p&gt;Along with this, a small group from my university of around 5–6 students have planned to work on our system design concepts, we have github repository from where we'll be doing system design and every 2 days we'll meet online and explain the concepts from our standpoints. Group work is much better than me doing it alone 😁 cause I want to actually do this now, after a  year of planning though 😶‍🌫️.&lt;/p&gt;

&lt;p&gt;And on weekends, I am finally, after 2 loong years of planning (procastination 😂), going to work towards my personal portfolio website! Yeah I have planned this but I hope I don't come in the way 😅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0diqt2gt5adlfaz3e1k.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0diqt2gt5adlfaz3e1k.gif" alt="A cartoon having 6 hands where each hand does some work indicating work overload or multi-tasking" width="384" height="480"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;So…,&lt;/p&gt;

&lt;p&gt;This vacation has a lot of work but I think I will keep blogging now and try to stay super consistent (that's my 5th time saying it right?).&lt;/p&gt;

&lt;p&gt;And yeah believe me when I say it, this is not it, I have a freelance work ongoing and also some more freelance work upcoming. So my schedule is going to be tight but full of fun (maybe?).&lt;/p&gt;

&lt;p&gt;I have built a fortress in my head, let's see what I can actually build 😁&lt;/p&gt;

&lt;p&gt;Signing off…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yuri639n3ip6af0b62v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yuri639n3ip6af0b62v.gif" alt="Bye GIF with a man disappearing" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you have read until here and have more time, I would really appreciate you giving a view at the other two platforms where I write as well 😅&lt;/p&gt;

&lt;p&gt;Hashnode:&amp;nbsp;&lt;a href="https://keep-alives.hashnode.dev/the-heartbeat-frame" rel="noopener noreferrer"&gt;https://keep-alives.hashnode.dev/the-heartbeat-frame&lt;/a&gt;&lt;br&gt;
Medium: &lt;a href="https://medium.com/@meetgandhi13062005/the-heartbeat-frame-0fe1e7bfb6a8" rel="noopener noreferrer"&gt;https://medium.com/@meetgandhi13062005/the-heartbeat-frame-0fe1e7bfb6a8&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>devjournal</category>
      <category>linux</category>
    </item>
    <item>
      <title>Contributing to Ubuntu — Day 6: Getting my MR merged!</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Mon, 02 Mar 2026 05:37:00 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/contributing-to-ubuntu-day-6-getting-my-mr-merged-4i9d</link>
      <guid>https://dev.to/geniusmind9999/contributing-to-ubuntu-day-6-getting-my-mr-merged-4i9d</guid>
      <description>&lt;p&gt;I know I am consistently losing my consistency of writing posts but this one is worth your time, really&amp;nbsp;;)&lt;/p&gt;

&lt;p&gt;So guess what? My merge request was finally ACCEPTED! What does this mean? Oh even I have to figure out that part 😂 but it just means there is still hope for open source!&lt;/p&gt;

&lt;p&gt;So last time I had commented on a PR multiple times (like an annoying kid waiting for you to get frustrated 😂) and also got myself embarassed on the matrix chat several times. And what happened now is just the amplification…&lt;/p&gt;

&lt;p&gt;Yeah literally, at the end of the post you may feel it is different but not so much 😁&lt;/p&gt;

&lt;p&gt;Anyways, for starters, I pushed that small 1 line change into my fork and then according to the reply on matrix from a maintainer whose name I won’t be able to give on the blog but he really felt like an angel throughout this whole process! And hence I opened a merge request.&lt;/p&gt;

&lt;p&gt;Yeah like an actual merge request just for a one liner 🫣&lt;/p&gt;

&lt;p&gt;And something amazing about gitlab’s merge request is that it automatically shows that in the related PR so if you go to that PR, you will see a MR by me! But a few days went by and it felt like everyone is happy ignoring me, except I did not want the hapiness to last longer. So I commented… again. And guess what? there was no response this time either 😂&lt;/p&gt;

&lt;p&gt;So after some more days, this was my approach (yeah, could have been better but hey no judging me 😅).&lt;/p&gt;

&lt;p&gt;So someone (can’t name them without their permission 😅) first told that they are awaiting their PR to be reviewed which they opened just 4 hours ago and then there were some more 6–7 messages solving the issue by calling in the correct maintainer, informing them and blah blah. So I thought to myself if someone with a PR opened 4 hours can get their issue solved so quickly, it should not take much time for someone like me who is waiting for over a month now and so my hands typed this message (trust me, if my brain was totally active at that time, I would not be writing the message!!)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Actually I also opened a MR in the gnome characters app but I am not getting any reply 😅&lt;br&gt;&lt;br&gt;
It’s been a week and I have also added 2 comments in the issue.&lt;br&gt;&lt;br&gt;
Would be glad if someone looked into it, just a small one line change nothing huge 😅&lt;/p&gt;

&lt;p&gt;This is the link:&lt;br&gt;&lt;br&gt;
&lt;a href="https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/56" rel="noopener noreferrer"&gt;https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/56&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I really wrote this message humbly and meant no harm; but credits to my insane luck, it sounded a bit off when you switch perspectives 😵‍💫&lt;/p&gt;

&lt;p&gt;(Maybe my username is a problem? Does Genius_Mind sound too arrogant for a username?!)&lt;/p&gt;

&lt;p&gt;So these were the next 2 messages in chat:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maintainer:&lt;/p&gt;

&lt;p&gt;Gentle reminder that we’re all volunteers, stretched thin, and that nobody is owed a review&lt;/p&gt;

&lt;p&gt;Me:&lt;/p&gt;

&lt;p&gt;I do agree, all of us do this in our free time but I just wanted to bring it into attention, did not mean anything else.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And there’s something more to it, remember there was this maintainer I tagged a month ago when I did not make any changes but wanted to? Yeah, Then it was their turn to see these messages…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maintainer:&lt;/p&gt;

&lt;p&gt;:Genius_Mind: reviewed the characters one; I was on a break at the time&lt;/p&gt;

&lt;p&gt;generally if you pinged me somewhere in january, please ping again because I guarantee I missed it&lt;/p&gt;

&lt;p&gt;I’ve been focusing on libadwaita stuff so far, since I’m being paid to do it but not characters, and since I was away for most of the january I kinda have to&amp;nbsp;&lt;/p&gt;

&lt;p&gt;either way, landed your MR  —  thanks!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the&amp;nbsp;&lt;strong&gt;:Genius_Mind&lt;/strong&gt; thing you see at the start is actually a tag to me its just how matrix does it (maybe element specifically but you get it)&lt;/p&gt;

&lt;p&gt;And according to this response from the maintainer, anyone who has a good level of communication would send the ideal message&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks a ton for closing the issue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But me being me, wrote something extra which was something I regretted later 🫣&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Me:&lt;/p&gt;

&lt;p&gt;Thanks a ton for closing the issue. I kinda got an idea that you were busy so I thought it would be best to wait. Anyways, this was it, thanks again!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this is true, when I was looking for other issues in the characters app, I did see a comment in a PR mentioning this maintainer being on leave for sometime so I decided to stay silent for sometime.&lt;/p&gt;

&lt;p&gt;But maybe my wording was bad or its just my amazing luck striking again, this was their response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maintainer:&lt;/p&gt;

&lt;p&gt;I was just on a break for mental health reasons, after that I was busy but still listening to pings — I just forgot to go through characters backlog, sorry&lt;/p&gt;

&lt;p&gt;Since I wa focusing on libadwaita instead&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🫣 Yeah… I think I could have had some control on my wording? Tone of a message just feels too important here, and unfortunately emoji's don't work I guess 😅&lt;/p&gt;

&lt;p&gt;I think you as a reader might also wish that I could undo the previous message 😂 but that's unfortunately out of my hands!&lt;/p&gt;

&lt;p&gt;But it does not end here, there’s another message I sent after this and I don’t know what to say about it, it just depends on what perspective you’re viewing it from…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Me:&lt;/p&gt;

&lt;p&gt;I understand dw! No need for sorries 🙂&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One part of me is okay with this message while the other wants me to quit open source right away, just trying to the hang of being an open source contributor I guess? 😅&lt;/p&gt;

&lt;p&gt;But even after all this the biggest regret I have is this (all in one image):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1m7kn1j2al4rh3zc4j14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1m7kn1j2al4rh3zc4j14.png" alt="Gitlab merge request showing the maintainer replacing my one line code change with their&amp;nbsp;own" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For someone who did not understand this, the maintainer understood my one line change and changed that one line change. So what I did was adding the version option after the constructor class, the maintainer moved it inside the constructor.&lt;/p&gt;

&lt;p&gt;Now this is a dilema cause when you have a one line change and the maintainer changes the location of the one line change in the code, it feels confusing whether I should call it my work or just another tuesday doing "collaboration" 😂. So I could ideally call this merge accepted but the contribution does not feel mine 😅.&lt;/p&gt;

&lt;p&gt;So I figured out everything from the flow to the code to even getting embarrased on element and yet got the merge request to complete but it just doesn’t feel like I have really earned it.&lt;/p&gt;

&lt;p&gt;So, I don’t know what I should call it but hey atleast I have an open source contribution! After all, I am looking forward to contributing to more issues on the characters app (or should I consider libadwaita now that the maintainer has mentioned it? I might get a job if I can convince them😜).&lt;/p&gt;

&lt;p&gt;But this MR merge taught me something new, it is not always your fault in communication, sometimes its just perspective that matters. And maybe this post might sound like me criticizing myself but that's important to keep me going cause according how much I know myself if I get satisfied in this MR, I am probably not gonna go further. But hey, celebration is also needed (and that was the opening 😂) and I do celebrate but more quietly instead of making a ton of noise!&lt;/p&gt;

&lt;p&gt;Also, this MR showed me how much a single maintainer has to juggle, I mean they are helping newcomers like me while having to do work that actually counts in their salary. Like amazing... literally!&lt;/p&gt;

&lt;p&gt;THANKS A LOT for reading till here and I really value your time, but if you are someone who has already gone through this, I would really like to know this in the comments. If possible please guide me or maybe just comment on how bad I am at something, I would appreciate that too 😁!&lt;/p&gt;

&lt;p&gt;Will keep you in the loop, byeee!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd8vtbjw4ub7ib2pc4rf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd8vtbjw4ub7ib2pc4rf.gif" alt="Bye GIF" width="200" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Credits: &lt;a href="https://tenor.com/view/ami-b%E1%BB%A5ng-b%E1%BB%B1-gif-4987291232759059685" rel="noopener noreferrer"&gt;https://tenor.com/view/ami-b%E1%BB%A5ng-b%E1%BB%B1-gif-4987291232759059685&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I also write on other platforms, if you like my blogs and are interested in keeping me motivated for writing more of these blogs you can just give a view to this same blog on the other two platforms 🙂&lt;/p&gt;

&lt;p&gt;Hashnode:&amp;nbsp;&lt;a href="https://contributing-to-ubuntu.hashnode.dev/contributing-to-ubuntu-day-final" rel="noopener noreferrer"&gt;https://contributing-to-ubuntu.hashnode.dev/contributing-to-ubuntu-day-final&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Medium: &lt;a href="https://medium.com/p/88c12c4fe875" rel="noopener noreferrer"&gt;https://medium.com/p/88c12c4fe875&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Day 5: The Guidance arrives... Finally!</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Fri, 06 Feb 2026 07:26:58 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/day-5-the-guidance-arrives-finally-2bbf</link>
      <guid>https://dev.to/geniusmind9999/day-5-the-guidance-arrives-finally-2bbf</guid>
      <description>&lt;p&gt;Firstly, thanks for reading this and secondly I finally got the flow of GNOME Open Source Contributions!&lt;/p&gt;

&lt;p&gt;So after a long time of getting ignored by the maintainers (not saying the maintainers don’t pay attention but there’s a ton of new issues popping up in the app I am trying to contribute to 😅), I decided to try out something else in GNOME and by something else I mean some other issue or maybe another app altogether.&lt;/p&gt;

&lt;p&gt;Hence I started looking for more issues with the &lt;code&gt;newcomers&lt;/code&gt; tag but sadly there were none other than the one I made the fix for 🥲. So I did what anyone would not have done, I just closed the window and started focusing on other stuff, come on what else would you expect from a BTech CSE student getting ignored for straight 2 weeks 😂&lt;/p&gt;

&lt;p&gt;But then yesterday (5th Feb), I opened gitlab again and seeing nothing I lost hope again but… I opened a new tab and searched this &lt;em&gt;how does contributing to GNOME work??&lt;/em&gt; And then I got this &lt;a href="https://handbook.gnome.org/" rel="noopener noreferrer"&gt;link&lt;/a&gt; as the 4th result which changed everything, literally!&lt;/p&gt;

&lt;p&gt;This was the GNOME Project Handbook made for guiding any one be it a newcomer or a maintainer. And I don’t even qualify for a newcomer yet 😂 so I did what I do best, I just read the whole page before I came across this &lt;a href="https://welcome.gnome.org/" rel="noopener noreferrer"&gt;link&lt;/a&gt; which is the link for the GNOME Welcome page which is meant to specifically guide beginners. I wish I had found this earlier 😂🥲&lt;/p&gt;

&lt;p&gt;The welcome page had a good amount of information but my eyes dragged right on the matrix chat for newcomers. Yeah there is an actual chat on the matrix for newcomers! Which I got to know so late 🧐&lt;/p&gt;

&lt;p&gt;So me being me I instantly joined the chat and sent this message:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hi there, I am Meet and I am looking forward to contributing to GNOME. Where can I find some instructions on the flow of making a contribution? (something like first create a PR or tag a maintainer in a PR to get assigned and then something else and then the contribution is merged into the main repo)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And there were 2 maintainers online (yeah so glad 😌) and one of them then replied making a conversation a bit interesting. I asked about the flow of contribution in GNOME and it was totally different than what I expected! The flow goes like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Find an issue where you think you can help&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check if someone is not already working on it (you can figure this out if the issue is simple yet there have been no comments for more than 2-3 weeks about making a fix on it)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create your fix in your own fork of the GNOME app repository&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a Merge Request and put the issue link or number in the description (yeah GitLab is smart enough to link the MR and the PR!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There might be changes to your proposed fix, do those&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The maintainer will finally accept the merge request&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have sucessfully contributed to GNOME, now go out enjoy and dance! 😂&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to step for a separate issue 🙃&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now after learning this I am ready to create a MR for the fix (which was a one liner waiting for almost a month now 🥲) which I will soon and let you guys know this in the upcoming blogs!&lt;/p&gt;

&lt;p&gt;But I also need some help from you dear reader, If you are motivated enough to read these blogs which are nothing more than my mood swings 😂 you might as well be ready to start your own blog series!! So just think about this for a minute or so, what if you started your own blog series on anything could be open source contributions, could be college related stuff or maybe even just a normal dev diary where you speak out loud on how you have been upskilling all these years and how you see your future self! Trust me it helps a lot more than it might sound 😂&lt;/p&gt;

&lt;p&gt;And if you do manage to start your own blog series I would definitely be a daily reader and I can promise that! Just put the link the comments and see your viewer count reach atleast 1 every time you write a blog!&lt;/p&gt;

&lt;p&gt;So now that I have learned from the professionals, its time to become atleast a newcomer in this open source world! I will be writing more so do keep reading, but for now byeee 👋&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fm%2FvJexcUuMCv8AAAAC%2Fvazei-bye.gif%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fm%2FvJexcUuMCv8AAAAC%2Fvazei-bye.gif%2520align%3D" alt="a little girl is going down a red slide" width="305" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Credits:&lt;/em&gt; &lt;a href="https://tenor.com/view/vazei-bye-leaving-goodbye-little-girl-gif-16362534" rel="noopener noreferrer"&gt;&lt;em&gt;Tenor&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Links to my blog on other platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Medium: &lt;a href="https://medium.com/@meetgandhi13062005/day-5-the-guidance-arrives-finally-c3352a8ab6ed" rel="noopener noreferrer"&gt;https://medium.com/@meetgandhi13062005/day-5-the-guidance-arrives-finally-c3352a8ab6ed&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hashnode: &lt;a href="https://contributing-to-ubuntu.hashnode.dev/day-5-the-guidance-arrives-finally" rel="noopener noreferrer"&gt;https://contributing-to-ubuntu.hashnode.dev/day-5-the-guidance-arrives-finally&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devjournal</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Contributing to Ubuntu — Day xyz: When I found the real open source</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Tue, 27 Jan 2026 08:42:42 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/contributing-to-ubuntu-day-xyz-when-i-found-the-real-open-source-1bph</link>
      <guid>https://dev.to/geniusmind9999/contributing-to-ubuntu-day-xyz-when-i-found-the-real-open-source-1bph</guid>
      <description>&lt;p&gt;Hello dear reader,&lt;/p&gt;

&lt;p&gt;I know you might be thinking that the title is a bit too dramatic, but what happened between today and the previous time I wrote is also similarly crazy 😂&lt;/p&gt;

&lt;p&gt;So, firstly I found an amazing issue on GitLab for GNOME, but as you might know, life is never a straight line for anyone 🥲 which obviously applies to me too. So I searched the web and also ChatGPT to look for ways to come up with the solution, it was difficult not because I was very new to GJS (yes, GNOME has its own version of JavaScript just to render things on your PC 🫠). So I first saw a bit of GJS documentation and it did not take me longer than an hour to realize the docs were almost useless, yeah I said it literally out loud when I was seeing the docs.&lt;/p&gt;

&lt;p&gt;The docs had the implementation part but that was not at all what I needed. So I turned to ChatGPT and it had performance issues if I put it in very simple words 😅. So I asked it to teach me GJS (which I do for almost all languages and frameworks whose docs overwhelm me, as a matter of fact, I learnt NextJS, Flutter and NodeJS from ChatGPT but polished it with docs and personal projects) and then it started listing facts about GJS, I knew learning from ChatGPT is a very iterative process of me explaining what I want and what I understood and &lt;strong&gt;hope&lt;/strong&gt; it just understands but this time ChatGPT decided to take a different route. It first told me the pros and cons of GJS, then why GNOME uses GJS, what I should do about it and a mixture of multiple “sorry” and “I apologise” messages that ChatGPT generally gives when either its training data is insufficient or my context is insufficient which is obvious, you cannot force a LLM to learn something not in its training data 😅 (though my friends have totally different arguments ready for this 😂).&lt;/p&gt;

&lt;p&gt;So then I started looking for help online again but using google search — “How does GJS start something“, “How do I write something in GJS“, “How to make my first app in GNOME Builder“, “What does GJS use in GNOME Builder“ and tons of similar questions of which none helped 😂 expectedly.&lt;/p&gt;

&lt;p&gt;So I just did what I could the best, I waited for 2 days for the reply of the comment I put in the issue. Yeah that was the only thing I could do then… 😅&lt;/p&gt;

&lt;p&gt;And guess what, I did not get a reply and hence I had to put in another message saying please read the first one 🙂, I mean come on that issue got a like after I put the comment, but not a reply 😓&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t9bl88ihom11p3zuacm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t9bl88ihom11p3zuacm.png" alt="GNOME GitLab Issue Screenshot" width="800" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If someone wants to view the full issue, here it is: &lt;a href="https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/56" rel="noopener noreferrer"&gt;https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/56&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finding this issue was not so easy and finding the actual maintainers to tag was another battle in itself! But even after this, I’m waiting — and learning patience. Once I get clarity from maintainers, I’ll either move forward with this issue or pivot again.&lt;/p&gt;

&lt;p&gt;Also, I just started writing on the platform called Medium because a lot of my friends recommended me for a better reach, so just check it out if you do have time, not major difference in feelings just the text 😂&lt;/p&gt;

&lt;p&gt;So these are the two other places I have my series going on, if you do have sometime and want to help me just visit these blogs too but you've already helped me a ton by reaching till the end&lt;/p&gt;

&lt;p&gt;Hashnode: &lt;a href="https://contributing-to-ubuntu.hashnode.dev/day-xyz-when-i-found-the-real-open-source" rel="noopener noreferrer"&gt;https://contributing-to-ubuntu.hashnode.dev/day-xyz-when-i-found-the-real-open-source&lt;/a&gt;&lt;br&gt;
Medium: &lt;a href="https://medium.com/@meetgandhi13062005/contributing-to-ubuntu-day-xyz-when-i-found-the-real-open-source-56b3913dca4b" rel="noopener noreferrer"&gt;https://medium.com/@meetgandhi13062005/contributing-to-ubuntu-day-xyz-when-i-found-the-real-open-source-56b3913dca4b&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s open source, I guess 🙂&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftenor.com%2Fsearch%2Fbye-bye-gifs" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftenor.com%2Fsearch%2Fbye-bye-gifs" alt="Bye Bye GIF" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
Credits: &lt;a href="https://tenor.com/search/bye-bye-gifs" rel="noopener noreferrer"&gt;Tenor&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Contributing to Ubuntu — Day 3: When I didn't touch code</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Wed, 17 Dec 2025 10:24:25 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/contributing-to-ubuntu-day-3-when-i-didnt-touch-code-202c</link>
      <guid>https://dev.to/geniusmind9999/contributing-to-ubuntu-day-3-when-i-didnt-touch-code-202c</guid>
      <description>&lt;p&gt;Okay so first of all — thanks a lot for reading this.&lt;br&gt;
Probably you are expecting me to do something with the &lt;code&gt;sl&lt;/code&gt; command, according to what I promised last time...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the next post, I’ll finally start modifying the train — maybe make it rainbow-colored or emoji-powered 🚂&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, I flipped 😅&lt;/p&gt;

&lt;p&gt;So this time I was away from code since my excitement to explore made me wander in the Ubuntu and GNOME community — Matrix chats, GitLab issues and discussions — which made me realize that code is just half the game, the other half is community interaction!&lt;/p&gt;

&lt;h2&gt;
  
  
  The silence:
&lt;/h2&gt;

&lt;p&gt;This exam week felt longer than it actually was, I mean time went a bit too slow for me.&lt;/p&gt;

&lt;p&gt;So I had 7 exams this semester and almost every exam went in a &lt;em&gt;not-so-good&lt;/em&gt; way 😅&lt;br&gt;
I studied hard starting from 2 days before the exams and during the exams. I also watched a movie the evening my last exam finished 😆. And finally I am back to my routine of exploring Ubuntu and documenting it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Work in the silence:
&lt;/h2&gt;

&lt;p&gt;During this period of silence where I did not write blogs and my exams weren't there (yeah, my exams finished just a week ago but I am also talking about the few days before the exam 🫠), I did not sit idle — I went to Google, ChatGPT and GitHub to look for what the Ubuntu community does and how they do it. So I searched about their contribution flow, it is fairly simple but yet difficult to wrap my head around since I never saw such a flow before 😅.&lt;br&gt;
I haven't understood everything and I know it (and you'll know it too when you read below 😅), but please feel free to correct me in the comments!&lt;br&gt;
The general flow goes like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You go to GitHub and clone their repo&lt;/li&gt;
&lt;li&gt;You first create an issue stating the problem or bug or whatever you found and add a comment saying "Please assign this issue to me" (not so sure on how you convince the maintainer though 😅)&lt;/li&gt;
&lt;li&gt;You wait for the maintainer to assign the issue to you&lt;/li&gt;
&lt;li&gt;When the issue is assigned to you, you start working on the fix&lt;/li&gt;
&lt;li&gt;First you discuss about the fix in the issue comment&lt;/li&gt;
&lt;li&gt;There will be some response from the community, when that happens, you iterate and ideate&lt;/li&gt;
&lt;li&gt;Once everyone agrees that you have a good idea, you implement it and push it in a new branch&lt;/li&gt;
&lt;li&gt;Once pushed, create a pr (pull request) and attach the pr link in the issue comment&lt;/li&gt;
&lt;li&gt;Let the community check your code, wait for testing to happen and improve on feedback&lt;/li&gt;
&lt;li&gt;That's it, once they finish their testing, they will merge the pr themselves (maybe, I have yet to figure this out since online sources don't tell me exactly this 😅)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So now you have an open source contribution in your name! And that too merged! But as usual there's a ton of pitfalls 🥲&lt;br&gt;
Firstly, if your issue is too big it might not even get accepted, leave alone getting assigned to you. So yeah I cannot directly open a pr saying 'Redesign the emoji picker', they'll just close the pr as if nothing happened!&lt;br&gt;
Secondly, this flow is approximately the general flow, it differs from project to project 🥲 — confusing, I know it, but helps get somewhere at least.&lt;br&gt;
So according to the online sources and some ChatGPT help I found that I should contribute to smaller issues and the community actually helps with those, there's issues with tags and for beginners like me, the 'good-first-issue' tag works great since it lets me contribute as well as gets me introduced to the community!&lt;/p&gt;

&lt;p&gt;So reading Ubuntu's docs, I found Matrix&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lhqq8kz34dcc8aa67kp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lhqq8kz34dcc8aa67kp.gif" alt="The matrix movie GIF" width="500" height="206"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;Credits: &lt;a href="https://media.giphy.com/media/v1.Y2lkPWVjZjA1ZTQ3czduNzhpajJtejliMXZnZnQ0NWl2YmJldDhyemg4M2x1ejNtNzF2byZlcD12MV9naWZzX3JlbGF0ZWQmY3Q9Zw/ip5L71rU6sjcc/giphy.gif" rel="noopener noreferrer"&gt;giphy&lt;/a&gt;&lt;/small&gt;&lt;br&gt;
Not this one though 😂. Matrix is a platform which I found similar to discord but the only difference is that the Ubuntu community uses that (couldn't find more 😅).&lt;br&gt;
So as a newcomer who was very anxious, I stared at the chat for straight 30 minutes just thinking what should be my first message. Finally I thought about this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hello everyone! I’m Meet, and I’m very new to open source contributions. I came across a couple of “good first issues” in the Open Documentation Academy repo, but I’m not fully sure how to get started with them.&lt;/p&gt;

&lt;p&gt;Could someone guide me on which one might be more suitable for a beginner, or how I should begin exploring them?&lt;/p&gt;

&lt;p&gt;These are the issues I found:&lt;br&gt;
&lt;a href="https://github.com/canonical/open-documentation-academy/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22%20no%3Aassignee" rel="noopener noreferrer"&gt;https://github.com/canonical/open-documentation-academy/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22%20no%3Aassignee&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And after this I waited for a day or so until someone really replied! And just by seeing the notification I got too overjoyed 😅&lt;br&gt;
So the reply was what you'd expect, they pointed out an issue saying this is something good you can try, but it really felt amazing to me at that moment 😁&lt;/p&gt;

&lt;p&gt;This was 2 days before my first exam though 🙂 — I just got a bit toooo bored I guess 😅&lt;/p&gt;

&lt;p&gt;But after my exams finished I explored the contribution related to that emoji picker (which, unfortunately for me, is a lot better in Ubuntu version 24 than it was in version 22) and I found that GNOME is actually the UI engine that runs in Ubuntu. I also found that the name &lt;em&gt;"Emoji Picker"&lt;/em&gt; that I been calling it is actually an app called the &lt;a href="https://gitlab.gnome.org/GNOME/gnome-characters" rel="noopener noreferrer"&gt;Characters App&lt;/a&gt; and it handles all this. So I thought for a bit and then created an account in GitLab, had the tokens and everything setup and cloned the repo in GNOME Builder app (which is pre-installed in Ubuntu just like the Characters App).&lt;/p&gt;

&lt;p&gt;After cloning, I went to GitLab and saw the open issues and started scanning the issue titles. I found two issues which I thought I could contribute to &lt;a href="https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/175" rel="noopener noreferrer"&gt;first issue&lt;/a&gt; and &lt;a href="https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/151" rel="noopener noreferrer"&gt;second issue&lt;/a&gt;. Then I searched for tags (searching how to search via tags was a different battle in itself for me 😅) and found &lt;a href="https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/56" rel="noopener noreferrer"&gt;this&lt;/a&gt; issue where newcomers could join in.&lt;br&gt;
So I decided to go with the &lt;a href="https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/151" rel="noopener noreferrer"&gt;second issue&lt;/a&gt; 🤓. I commented in the issue saying that this bug does not exist in my system — except, I did not give any system specs 😅. But surprisingly, the issue had another comment in 2 days saying it is still glitchy in some other machine (and this guy gave specs). So because of me an issue that was inactive since 2 months finally started to have a conversation going on.&lt;br&gt;
The chat went on for 3-4 days, not a long one though, and the issue was first closed and then reopened because they found a bug! And yeah, I am thinking of contributing to fixing that bug...&lt;br&gt;
Just after doing the "&lt;a href="https://gitlab.gnome.org/GNOME/gnome-characters/-/issues/56" rel="noopener noreferrer"&gt;this&lt;/a&gt;" contribution 😅&lt;/p&gt;

&lt;p&gt;So finally I am a bit confident about my step of going into the open-source world of GNOME and Ubuntu but I am just as anxious 😅&lt;br&gt;
Can't wait to see what's next though 😁&lt;/p&gt;

&lt;h2&gt;
  
  
  What this taught me
&lt;/h2&gt;

&lt;p&gt;This experience taught me something better, sometimes there are a lot of things which cannot happen without people collaborating and talking on it or maybe even arguing if necessary and I hope to be a part of at least one argument 😁 (even if just once).&lt;br&gt;
Not touching code taught me a lot of human perspective in the open-source world now let's see what touching code can teach me 😂&lt;br&gt;
But anyone who is reading this maybe for starting from scratch like me, I just want to tell you, it is better to understand the community before we can begin to understand the Kernel 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks a ton for the time mate! I really appreciate you came until here, stay tuned till the next time where I might code and even help with some issues! Super excited yet somehow nervous 😁&lt;br&gt;
Just love the open-source vibes!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9dvwt0lkreuk3xpdnhd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9dvwt0lkreuk3xpdnhd.gif" alt="Its all about the vibes - Simpsons Bart GIF" width="498" height="373"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;Credits: &lt;a href="https://media1.tenor.com/m/1CcXIDK6YboAAAAC/the-simpsons-bart.gif" rel="noopener noreferrer"&gt;tenor&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devjournal</category>
      <category>ubuntu</category>
      <category>community</category>
    </item>
    <item>
      <title>Contributing to Ubuntu — Day 2.5: When I had to pause my journey ⏸️</title>
      <dc:creator>Meet Gandhi</dc:creator>
      <pubDate>Mon, 10 Nov 2025 06:31:52 +0000</pubDate>
      <link>https://dev.to/geniusmind9999/contributing-to-ubuntu-day-25-when-i-had-to-pause-my-journey-55b</link>
      <guid>https://dev.to/geniusmind9999/contributing-to-ubuntu-day-25-when-i-had-to-pause-my-journey-55b</guid>
      <description>&lt;p&gt;Hello people! I know you would want to hit me hard in the face for not writing a blog for a week (I know I am not that important but I can always pretend so 😁) but I will be as honest I can in this one.&lt;/p&gt;




&lt;h2&gt;
  
  
  What happened to my excitement?
&lt;/h2&gt;

&lt;p&gt;My excitement is at its place but my end semester exams are coming close. Due to them I have to slow down my blogs a bit and also sacrifice my ubuntu exploration 🥲. So just like any good engineering student, I also over burdened myself with a ton of heavy courses this semester along with a number of other side activities (yeah, I also wanted to type the word &lt;strong&gt;side-kick&lt;/strong&gt; here 😂). So now if I do not get to studying, the examiners in the exam hall will laugh looking at my blank answer shit (that is not a typo!).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71s05oqofuwmrcwt3wyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71s05oqofuwmrcwt3wyq.png" alt="Mr. Bean trying to not look at the questions but looks and gets frustrated" width="220" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But I want to geniuinely continue this exploration as I have recently fallen in love — with &lt;strong&gt;Operating Systems&lt;/strong&gt; 🙃 and I do plan to change my career in that direction. So you'd say, what is the worst you could have done in your life that you have to give up your passion right? I thought the same a month ago 🫠&lt;/p&gt;




&lt;h2&gt;
  
  
  Why should passion suffer?
&lt;/h2&gt;

&lt;p&gt;So the dumbest thing I can do to help my future self is take a course so tough it literally questions my existence!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8ugpdaatrft5ni0pyjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8ugpdaatrft5ni0pyjo.png" alt="Me recalling my self taking some courses just for fun and crying" width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, in my third year, I’ve somehow managed to stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;9 college courses ☠️,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An internship (yes, it pays 😎),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;IEEE student branch work,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and a programming club role&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So yeah... I probably shouldn’t have started this blog series with that much on my plate. But honestly? I’m glad I did. Because even if I had to pause at Day 2 — I know I’ll be back after 7th December (post-exams 🫠).&lt;/p&gt;




&lt;h2&gt;
  
  
  What are my plans next?
&lt;/h2&gt;

&lt;p&gt;So my next plans are a change of mind, I think tinkering with the &lt;code&gt;sl&lt;/code&gt; command might teach me something new but the journey feels a bit slow to me. So maybe I will make some small changes and get to exploring how to package this command into a &lt;code&gt;.deb&lt;/code&gt; which is I think a good achievement. After I finish that, I am planning to create a new issue on ubuntu for their emoji menu looking so bad. If the maintainer is in a good mood I may get assigned or my issue might get deleted 😶‍🌫️. In that case... I will create another issue! No issues from my side 😂&lt;/p&gt;

&lt;p&gt;And for the long term plans, I was thinking of understanding the internals of ubuntu, like how memory management and all works but I know my interests will change (can't blame me, I am a Gemini 😅 — not Google Gemini, my zodiac sign in Gemini) but those interest changes will be local, in a global view I would like to pursue a career in OS development or System Design since both are my favourites!&lt;/p&gt;

&lt;p&gt;And also, you may see some delay in blogs in december since I will be going out for a vacation! So yeah, I have asked for a leave officially and you have to approve it (please 😅).&lt;/p&gt;




&lt;h2&gt;
  
  
  Now what?
&lt;/h2&gt;

&lt;p&gt;Now what, nothing, go back to work while I go back to studying, we don't have much time to spare remember? Or atleast I do not 🙃 So hang in tight, since everytime I remember this blog series, I get an adrenaline rush and I promise myself that I have to make the ubuntu emoji picker the best one yet!!&lt;/p&gt;

&lt;p&gt;In case, you have any interesting idea, please let me know in the comments and if you are as crazy as me I would even try that out!&lt;/p&gt;

&lt;p&gt;Thanks for reading through! Sayonara!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabeupcy70664npjbz1ql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabeupcy70664npjbz1ql.png" alt="a picture of a minion holding a teddy bear and a mouse with the words bye-bye below him" width="220" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>studentlife</category>
      <category>osdev</category>
    </item>
  </channel>
</rss>
