<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Tanmoy Sarkar]]></title><description><![CDATA[I am exploring the world of technology and playing with them. Like a kid, want to break them and create new ones. I will continue to write blogs to make develop]]></description><link>https://blog.tanmoysrt.xyz</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 13:21:05 GMT</lastBuildDate><atom:link href="https://blog.tanmoysrt.xyz/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Swiftwave PaaS: One Year in Development]]></title><description><![CDATA[From last year (July~August), I am working on an open source PaaS to deploy and manage applications easily on any VPS. I have a motive to create a solution which you once setup on your cloud, you will get same kind of experience like other platforms ...]]></description><link>https://blog.tanmoysrt.xyz/swiftwave-paas-one-year-in-development</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/swiftwave-paas-one-year-in-development</guid><category><![CDATA[Devops]]></category><category><![CDATA[PaaS]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Haproxy]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Mon, 24 Jun 2024 14:19:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719238627025/f1d58b1b-634c-4db9-a9c9-bc4afe457640.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>From last year (July~August), I am working on an open source PaaS to deploy and manage applications easily on any VPS. I have a motive to create a solution which you once setup on your cloud, you will get same kind of experience like other platforms like Heroku, Railway or Render.</p>
<h2 id="heading-little-bit-about-the-project-swiftwave">Little bit about the project - SwiftWave</h2>
<p>SwiftWave is a self-hosted lightweight PaaS solution to deploy and manage your applications on any VPS.</p>
<p>Website - <a target="_blank" href="https://swiftwave.org/">https://swiftwave.org/</a> Github - <a target="_blank" href="https://github.com/swiftwave-org/swiftwave">https://github.com/swiftwave-org/swiftwave</a> If you like the intiative give it a ⭐ star in GitHub.</p>
<h2 id="heading-why-did-i-decide-to-start-developing-this-open-source-paas">Why did I decide to start developing this open source PaaS?</h2>
<p><strong>Incentive Motive</strong> - I am absolutely exhausted from doing LeetCode. I don't usually enjoy CP or Leetcode, but need to do for placements. I began questioning if I really had a problem being consistent for long time (at-least 6 months). I therefore made an effort to push myself to create a project that I will stick with for a very long period.</p>
<p><strong>Passive Motive</strong> - I like development and computer science core concepts so much and on every week build something for just fun or for hackathon. Anyway I don't want to spare money for deployment, so used Heroku, then moved to AWS EC2 (free tier) after getting familarized with linux. Many times my friends reach out to me for deploying in EC2.</p>
<p>While I was learning k8s and preparing for CKA, I amazed by it's internals &amp; started thinking to build something lightweight with cool UI/UX. That's where it all get started.</p>
<p><strong>Target of Building Swiftwave</strong> -</p>
<ul>
<li><p><strong>Being lightweight</strong> : Swiftwave + Postgres + HAProxy + UDP Proxy = ~180MB of system. So leaving a lot of room for your deployed apps.</p>
</li>
<li><p><strong>Scalable</strong> : This isn't meant for huge-scale operations - Kubernetes handles that. Instead, it's aimed at meeting the needs of small startups, individual users, home labs, and internal company tools.</p>
</li>
<li><p><strong>Full-Featured</strong>: Swiftwave offers a wide range of capabilities. Visit <a target="_blank" href="http://swiftwave.org">swiftwave.org</a> to explore all the features available in the platform.</p>
</li>
</ul>
<h2 id="heading-sprint-vs-continuous-development">Sprint vs Continuous Development</h2>
<p>Before this project, I always go in Hackathon Mode for building project, giving all my free time. After launching the project, I often lost the motivation to keep maintaining it.</p>
<p>With Swiftwave, I started the same way but quickly realized this approach wouldn't work long-term. So, I switched it. For the first time, I tried a more structured approach, dedicating a consistent 1 to 1.5 hours daily to the project. This method proved effective. After a year of steady effort, we've successfully released a stable version of Swiftwave.</p>
<blockquote>
<p>A small effort every day builds more than occasional bursts of productivity.</p>
</blockquote>
<h2 id="heading-dsa-is-not-useless">DSA is not useless</h2>
<p>While I initially expressed disinterest in LeetCode, I don't find Data Structures and Algorithms (DSA) boring or unimportant. Many people think DSA is only useful for job interviews, but that's not the case.</p>
<p>Over the past year, I've applied DSA concepts in various parts of my projects. This experience has shown me that DSA knowledge is crucial in software development. However, it's worth noting that real-world problem-solving often takes more time than the quick solutions expected in interview.</p>
<p>For instance, in Swiftwave, we implemented a feature for uploading code directly to deploy apps. On the frontend, we create a tar archive of the project to send to the server. For NodeJS apps, we needed to exclude the 'node_modules' and other folder by following .gitignore rules.</p>
<p>Our first attempt at this was inefficient, taking about 30 seconds just to scan files, apply ignore rules, and create the archive.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q4ot5lhf70waji54t38v.png" alt="Worst Performance of tart" /></p>
<p>In the end, we used a tree-based method to organize files and handle .gitignore rules. This new approach was much faster, finishing everything in about half a second."</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wuvuisko636d34a45dgo.png" alt="Superb Performance of tartplus" /></p>
<p><strong>Source Code of tartplus</strong> - <a target="_blank" href="https://github.com/swiftwave-org/tartplus">https://github.com/swiftwave-org/tartplus</a></p>
<h2 id="heading-automation-is-a-must">Automation is a Must</h2>
<p>For those starting an open source project with long-term maintenance in mind, automation is crucial. Initially, it's often a one person project or the work of a very small team.</p>
<p>Alongside maintaining a OSS project, maintainers have their full time job or academics. So, It's vital to automate all repetitive tasks, allowing maintainers to focus solely on coding and reviews.</p>
<p>In swiftwave, we have various things -</p>
<ul>
<li><p>*.<a target="_blank" href="http://swiftwave.xyz">swiftwave.xyz</a> DNS Resolver</p>
</li>
<li><p>APT Repository - <a target="_blank" href="http://deb.repo.swiftwave.org/">http://deb.repo.swiftwave.org/</a></p>
</li>
<li><p>RPM Repository - <a target="_blank" href="http://rpm.repo.swiftwave.org/">http://rpm.repo.swiftwave.org/</a></p>
</li>
<li><p>Custom build images for some one-click apps - <a target="_blank" href="https://github.com/swiftwave-org/app-store">https://github.com/swiftwave-org/app-store</a></p>
</li>
<li><p>Deployment of documentation and websites</p>
</li>
</ul>
<p>All these processes are automated.</p>
<p>For instance, I usually do a weekly release. I only need to draft and publish the release. Building APT &amp; RPM packages for different architectures and uploading them to the repository server are all automated.</p>
<p>We primarily use Github Actions for nearly all our automation needs.</p>
<h2 id="heading-testcases-boring-but-gives-peace-of-mind">Testcases boring but gives peace of mind</h2>
<p>When I first started contributing to open source last year, I was assigned in some issues for writing test cases for software. I also had to write integration tests during my GSoC'23 project with CircuitVerse. Back then, I found writing tests tedious.</p>
<p>However, now that I'm developing my project, my perspective has changed. I've realized how crucial it is to write tests and increase code coverage. With good coverage, I don't need to manually check if features are affected by changes.</p>
<p>For software like Swiftwave, which users install on their own servers, a buggy release could seriously disrupt their systems. It's essential to ensure nothing breaks in stable releases. Having numerous test cases makes this process smoother and more efficient.</p>
<h2 id="heading-its-not-bad-at-all-to-reinvent-the-wheel">It's not bad at all to reinvent the wheel</h2>
<p>Sometimes, creating your own solution can be beneficial. Swiftwave needed a pubsub system and queueing mechanism. While RabbitMQ and Redis are common choices, they use up valuable server resources, leaving less for deployed apps.</p>
<p>My solution? I built an in-memory pubsub and persistent task queueing system with using goroutines. This approach uses minimal resources. As a result, Swiftwave typically runs using only about 45MB of RAM.</p>
<p>Swiftwave with all this things takes ~45MB of ram most of the time.</p>
<p>However, we've kept it flexible. Users can still configure Swiftwave to use Redis or RabbitMQ instead of the built-in system if they prefer.</p>
<h2 id="heading-changes-in-pov-of-open-source">Changes in POV of Open Source</h2>
<p>In the 'Indian YouTube Space', there's often too much focus on just contributing to open source, which might have changed what open source is really about. I used to think this way too.</p>
<p>Contributing to open source shouldn't feel forced. Here's a better approach:</p>
<ul>
<li><p>Start by using open source software</p>
</li>
<li><p>Keep using it if you like it</p>
</li>
<li><p>If you find an issue or want a new feature, try to help fix or add it</p>
</li>
<li><p>Create your own open source projects that can help others</p>
</li>
<li><p>If a project dependency isn't working well, try to fix its issues</p>
</li>
<li><p>Engage in conversations and forums, helping others who are stuck</p>
</li>
</ul>
<p>Project Maintainers, Creator become more happy when you use their products.</p>
<h2 id="heading-why-open-source-code-matters">Why Open Source code matters ?</h2>
<p>Swiftwave is primarily built on two key softwares: Docker Swarm and HAProxy.</p>
<p>To develop various features, I had to understand how these tools work. This led me to explore several repositories:</p>
<ul>
<li><p>Docker Engine - <a target="_blank" href="https://github.com/moby/moby">https://github.com/moby/moby</a></p>
</li>
<li><p>Docker CLI - <a target="_blank" href="https://github.com/docker/cli">https://github.com/docker/cli</a></p>
</li>
<li><p>Libnetwork - <a target="_blank" href="https://github.com/moby/libnetwork">https://github.com/moby/libnetwork</a></p>
</li>
<li><p>HAProxy DataplaneAPI - <a target="_blank" href="https://github.com/haproxytech/dataplaneapi">https://github.com/haproxytech/dataplaneapi</a></p>
</li>
</ul>
<p>One particular challenge was implementing direct SSH support for applications. I delved into the code for 'docker exec', which was quite complex. After grasping the concept, I was able to implement a similar feature in Swiftwave.</p>
<h2 id="heading-the-end">The End</h2>
<p>Developing Swiftwave has been an exciting and challenging journey that I want to continue long-term. It has been a great learning experience for me.</p>
<p>There's still lot of rooms for improvement in Swiftwave to make it an even more dependable deployment tool. We have many areas we'd like to enhance in the future.</p>
<hr />
<p>Website - <a target="_blank" href="https://swiftwave.org/">https://swiftwave.org/</a> Github - <a target="_blank" href="https://github.com/swiftwave-org/swiftwave">https://github.com/swiftwave-org/swiftwave</a> If you like the intiative give it a ⭐ star in GitHub.</p>
]]></content:encoded></item><item><title><![CDATA[Week 9, 10 & 11 - CircuitVerse@GSOC'23]]></title><description><![CDATA[This blog is coming after a long time [almost 3 weeks].
Throughout this week, the main tasks involved were -

Update the docker setup to make it more convenient

Test the docker setup in all OS [Linux, Mac, Windows]

Rewrite Documentation


Revamp Do...]]></description><link>https://blog.tanmoysrt.xyz/week-9-10-11-circuitversegsoc23</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/week-9-10-11-circuitversegsoc23</guid><category><![CDATA[Docker]]></category><category><![CDATA[CircuitVerse]]></category><category><![CDATA[gsoc]]></category><category><![CDATA[Heroku]]></category><category><![CDATA[swiftwave]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sun, 20 Aug 2023 18:55:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1692550828088/e21b9370-fb2e-4ec1-9ef6-b0a58d035a66.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This blog is coming after a long time [almost 3 weeks].</p>
<p>Throughout this week, the main tasks involved were -</p>
<ul>
<li><p>Update the docker setup to make it more convenient</p>
</li>
<li><p>Test the docker setup in all OS [Linux, Mac, Windows]</p>
</li>
<li><p>Rewrite Documentation</p>
</li>
</ul>
<h4 id="heading-revamp-docker-setup">Revamp Docker Setup</h4>
<p>The main problems with the current setup are -</p>
<ol>
<li><p>In the docker file, it copies all the source code and installs dependencies</p>
</li>
<li><p>The image and process inside the container run as root user</p>
</li>
<li><p>For this reason, whenever some dependencies or codebase changes the docker image rebuild and which takes lots of time</p>
</li>
<li><p>As the process runs as a root user, some file changes from the container give permission errors in a code editor.</p>
</li>
<li><p>As we install all the dependencies at the time of building the image, there is no possibility to cache the dependencies</p>
</li>
</ol>
<p><strong>Solution -</strong></p>
<p>The solution is inspired by the <strong>GitHub Codespaces</strong> working principle.</p>
<p><strong>👀 How do codespaces work?</strong></p>
<ol>
<li><p>It has a Dockerfile of the application</p>
</li>
<li><p>It starts the container with a <code>sleep infinity</code> to prevent it from terminating after the start</p>
</li>
<li><p>Then, it uses <code>attach</code> or <code>exec</code> to attach the container</p>
</li>
<li><p>Then, it runs a <code>setup.sh</code> to install all dependencies and prepare the4 environment</p>
</li>
<li><p>Then it runs <code>boot.sh</code> to start the application</p>
</li>
</ol>
<p><strong>🏄 Let's do the same for CircuitVerse project</strong></p>
<ol>
<li><p>Prepare the Dockerfile. This will only contain the ruby and nodejs environment. As well as it will have a non-root user with the same user id and group id of the host.</p>
<p> We will provide host's group id and user id by build arguments</p>
<pre><code class="lang-dockerfile"> <span class="hljs-keyword">FROM</span> ruby:<span class="hljs-number">3.2</span>.<span class="hljs-number">1</span>

 <span class="hljs-comment"># Args</span>
 <span class="hljs-keyword">ARG</span> NON_ROOT_USER_ID
 <span class="hljs-keyword">ARG</span> NON_ROOT_GROUP_ID
 <span class="hljs-keyword">ARG</span> NON_ROOT_USERNAME
 <span class="hljs-keyword">ARG</span> NON_ROOT_GROUPNAME
 <span class="hljs-keyword">ARG</span> OPERATING_SYSTEM

 <span class="hljs-comment"># Check mandatory args</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">test</span> -n <span class="hljs-string">"<span class="hljs-variable">$NON_ROOT_USER_ID</span>"</span></span>
 <span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">test</span> -n <span class="hljs-string">"<span class="hljs-variable">$NON_ROOT_GROUP_ID</span>"</span></span>
 <span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">test</span> -n <span class="hljs-string">"<span class="hljs-variable">$OPERATING_SYSTEM</span>"</span></span>
 <span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">test</span> -n <span class="hljs-string">"<span class="hljs-variable">$NON_ROOT_USERNAME</span>"</span></span>
 <span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">test</span> -n <span class="hljs-string">"<span class="hljs-variable">$NON_ROOT_GROUPNAME</span>"</span></span>

 <span class="hljs-comment"># Create app directory</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> mkdir /circuitverse</span>
 <span class="hljs-comment"># Create non-root user directory</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> mkdir /home/<span class="hljs-variable">${NON_ROOT_USERNAME}</span></span>
 <span class="hljs-comment"># Create non-root vendor directory</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> mkdir /home/vendor</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> mkdir /home/vendor/bundle</span>
 <span class="hljs-comment"># set up workdir</span>
 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /circuitverse</span>

 <span class="hljs-comment"># Set shell to bash</span>
 <span class="hljs-keyword">SHELL</span><span class="bash"> [<span class="hljs-string">"/bin/bash"</span>, <span class="hljs-string">"-c"</span>]</span>

 <span class="hljs-comment"># install dependencies</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> apt-get update -qq &amp;&amp; \
  apt-get install -y imagemagick shared-mime-info libvips sudo make cmake netcat libnotify-dev git chromium-driver chromium --fix-missing &amp;&amp; apt-get clean</span>

 <span class="hljs-comment"># Setup nodejs and yarn</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> curl -sL https://deb.nodesource.com/setup_16.x | bash \
  &amp;&amp; apt-get update &amp;&amp; apt-get install -y nodejs &amp;&amp; rm -rf /var/lib/apt/lists/* \
  &amp;&amp; curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  &amp;&amp; <span class="hljs-built_in">echo</span> <span class="hljs-string">"deb https://dl.yarnpkg.com/debian/ stable main"</span> | tee /etc/apt/sources.list.d/yarn.list \
  &amp;&amp; apt-get update &amp;&amp; apt-get install -y yarn &amp;&amp; rm -rf /var/lib/apt/lists/*</span>

 <span class="hljs-comment"># If OPERATING_SYSTEM is Linux, create non-root user</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">$OPERATING_SYSTEM</span>"</span> == <span class="hljs-string">"linux"</span> ]]; <span class="hljs-keyword">then</span> \
     <span class="hljs-comment"># create non-root user with same uid:gid as host non-root user</span></span>
     groupadd -g ${NON_ROOT_GROUP_ID} -r ${NON_ROOT_GROUPNAME} &amp;&amp; useradd -u ${NON_ROOT_USER_ID} -r -g ${NON_ROOT_GROUPNAME} ${NON_ROOT_USERNAME} \
     &amp;&amp; chown -R ${NON_ROOT_USERNAME}:${NON_ROOT_GROUPNAME} /circuitverse \
     &amp;&amp; chown -R ${NON_ROOT_USERNAME}:${NON_ROOT_GROUPNAME} /home/${NON_ROOT_USERNAME} \
     &amp;&amp; chown -R ${NON_ROOT_USERNAME}:${NON_ROOT_GROUPNAME} /home/vendor \
     &amp;&amp; chown -R ${NON_ROOT_USERNAME}:${NON_ROOT_GROUPNAME} /home/vendor/bundle \
     <span class="hljs-comment"># Provide sudo permissions to non-root user</span>
     &amp;&amp; adduser ${NON_ROOT_USERNAME} sudo \
     &amp;&amp; echo <span class="hljs-string">'%sudo ALL=(ALL) NOPASSWD:ALL'</span> &gt;&gt; /etc/sudoers ;\
 fi

 <span class="hljs-comment"># Switch to non-root user</span>
 <span class="hljs-keyword">USER</span> ${NON_ROOT_USERNAME}
</code></pre>
<blockquote>
<p>For <code>macOS</code> and <code>windows</code> we don't need non-root users because the volume mounting is worked as shared storage. So the permission error will not come</p>
</blockquote>
</li>
<li><p>Next, we create a <code>setup.sh</code> which will install dependencies and migrate the database</p>
<pre><code class="lang-bash"> <span class="hljs-comment"># !/bin/sh</span>

 <span class="hljs-comment"># Remove tmp folder</span>
 rm -rf /circuitverse/tmp

 <span class="hljs-comment"># Install ruby dependencies</span>
 gem install bundler
 bundle config <span class="hljs-built_in">set</span> --<span class="hljs-built_in">local</span> without <span class="hljs-string">"production"</span>
 bundle config <span class="hljs-built_in">set</span> --<span class="hljs-built_in">local</span> path <span class="hljs-string">"/home/vendor/bundle"</span>
 bundle install
 <span class="hljs-comment"># Install node dependencies</span>
 yarn
 <span class="hljs-comment"># Setup database</span>
 bundle <span class="hljs-built_in">exec</span> rails db:create
 bundle <span class="hljs-built_in">exec</span> rails db:schema:load
 bundle <span class="hljs-built_in">exec</span> rails db:migrate
 bundle <span class="hljs-built_in">exec</span> rails db:seed
 <span class="hljs-comment"># generate key-pair for jwt-auth</span>
 <span class="hljs-comment"># if private.pem and public.pem does not exists</span>
 <span class="hljs-keyword">if</span> [ ! -f <span class="hljs-string">"/circuitverse/config/private.pem"</span> ] &amp;&amp; [ ! -f <span class="hljs-string">"/circuitverse/config/public.pem"</span> ]; <span class="hljs-keyword">then</span>
   openssl genrsa -out /circuitverse/config/private.pem 2048
   openssl rsa -<span class="hljs-keyword">in</span> /circuitverse/config/private.pem -outform PEM -pubout -out /circuitverse/config/public.pem
 <span class="hljs-keyword">fi</span>
</code></pre>
</li>
<li><p>Then we create a <code>boot.sh</code> to initiate <code>setup.sh</code> and then start the server</p>
<pre><code class="lang-bash"> <span class="hljs-comment">#!/bin/bash</span>

 <span class="hljs-comment"># Delete server.pid if it exists</span>
 rm -f /circuitverse/tmp/pids/server.pid 2&gt;&amp;1

 <span class="hljs-comment"># Run setup</span>
 <span class="hljs-built_in">echo</span> <span class="hljs-string">"Setup project"</span>
 ./bin/docker/setup

 <span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">$OPERATING_SYSTEM</span>"</span> == <span class="hljs-string">"linux"</span> || <span class="hljs-string">"<span class="hljs-variable">$OPERATING_SYSTEM</span>"</span> == <span class="hljs-string">"mac"</span> ]]; <span class="hljs-keyword">then</span>
   <span class="hljs-keyword">if</span> [ ! -d <span class="hljs-string">"<span class="hljs-variable">${HOST_CURRENT_DIRECTORY%/*}</span>"</span> ]; <span class="hljs-keyword">then</span>
     sudo mkdir -p <span class="hljs-string">"<span class="hljs-variable">${HOST_CURRENT_DIRECTORY%/*}</span>"</span>
   <span class="hljs-keyword">fi</span>
   <span class="hljs-comment"># Setup symbolic link for solargraph</span>
   <span class="hljs-keyword">if</span> [ ! -L <span class="hljs-string">"<span class="hljs-variable">$HOST_CURRENT_DIRECTORY</span>"</span> ]; <span class="hljs-keyword">then</span>
     sudo ln -s -T /circuitverse <span class="hljs-string">"<span class="hljs-variable">$HOST_CURRENT_DIRECTORY</span>"</span>
   <span class="hljs-keyword">fi</span>
   <span class="hljs-comment"># Start solargraph server in background</span>
   bundle <span class="hljs-built_in">exec</span> solargraph socket --host=<span class="hljs-string">"0.0.0.0"</span> --port=3002 &amp;&gt; /dev/null &amp;
 <span class="hljs-keyword">fi</span>

 <span class="hljs-comment"># Start server</span>
 ./bin/dev

 <span class="hljs-comment"># Start bash if previous command exits</span>
 /bin/bash
</code></pre>
</li>
<li><p>Now, we need to prepare the <code>docker-compose.yml</code>. As you can see still now we haven't copied the source code in the image or anywhere.</p>
<p> We will mount the codebase to the container at <strong>/circuitverse</strong> location to make it easy to edit files and keep all files in sync</p>
<pre><code class="lang-dockerfile"> ....
   web:
     build:
       context: .
       dockerfile: Dockerfile
       args:
         - NON_ROOT_USER_ID=${CURRENT_UID}
         - NON_ROOT_GROUP_ID=${CURRENT_GID}
         - OPERATING_SYSTEM=${OPERATING_SYSTEM}
         - NON_ROOT_USERNAME=${NON_ROOT_USERNAME}
         - NON_ROOT_GROUPNAME=${NON_ROOT_GROUPNAME}
     command: sleep infinity
     volumes:
       - .:/circuitverse:rw
       - ./config/database.docker.yml:/circuitverse/config/database.yml:rw
       - ruby_bundle:/home/vendor/bundle:rw
     cap_add:
       - SYS_ADMIN
     ports:
       - <span class="hljs-string">"3000:3000"</span>
       - <span class="hljs-string">"3001:3001"</span>
       - <span class="hljs-string">"3002:3002"</span>
       - <span class="hljs-string">"3035:3035"</span>
       - <span class="hljs-string">"3036:3036"</span>
     depends_on:
       - db
       - redis
     environment:
       REDIS_URL: <span class="hljs-string">"redis://redis:6379/0"</span>
       CIRCUITVERSE_USE_SOLR: <span class="hljs-string">"false"</span>
       DOCKER_ENVIRONMENT: <span class="hljs-string">"true"</span>
       NODE_ENV: <span class="hljs-string">"development"</span>
       HOST_CURRENT_DIRECTORY: $PWD
       OPERATING_SYSTEM: $OPERATING_SYSTEM
 ....
</code></pre>
</li>
<li><p>Everything is ready. But there is an issue, we can't run this using <code>docker-compose up</code>. We need to set the <code>NON_ROOT_USER_ID</code> <code>NON_ROOT_GROUP_ID</code> <code>OPERATING_SYSTEM</code> environment variables. Also, need to start the server by attaching to it. So write a script for that</p>
<pre><code class="lang-dockerfile"> <span class="hljs-comment">#!/bin/bash</span>

 <span class="hljs-comment"># Detect operating system [linux, macos] with uname</span>
 DETECTED_OS=$(uname -s | tr <span class="hljs-string">'[:upper:]'</span> <span class="hljs-string">'[:lower:]'</span>)

 <span class="hljs-comment"># If operating system is linux</span>
 if [ <span class="hljs-string">"$DETECTED_OS"</span> = <span class="hljs-string">"linux"</span> ]; then
   <span class="hljs-comment"># Set environment variables temporary</span>
   export CURRENT_GID=$(id -g)
   export CURRENT_UID=$(id -u)
   export NON_ROOT_USERNAME=<span class="hljs-string">"user"</span>
   export NON_ROOT_GROUPNAME=<span class="hljs-string">"user"</span>
   export OPERATING_SYSTEM=<span class="hljs-string">"linux"</span>
   <span class="hljs-comment"># Check if docker and docker compose are installed</span>
   if ! command -v docker &amp;&gt;/dev/null; then
     echo <span class="hljs-string">"Docker is not installed. Install docker : https://docs.docker.com/engine/install/"</span>
     exit <span class="hljs-number">0</span>
   fi
   <span class="hljs-comment"># Check if rootless docker is available</span>
   if docker ps &amp;&gt;/dev/null; then
     <span class="hljs-comment"># Run docker-compose up</span>
     docker compose up -d --build
     <span class="hljs-comment"># Run docker-compose exec web bash</span>
     docker compose exec web bin/docker/boot
     <span class="hljs-comment"># Run docker-compose down</span>
     docker compose down
   else
     <span class="hljs-comment"># Run docker-compose up as root user</span>
     sudo docker compose up -d --build
     <span class="hljs-comment"># Run docker-compose exec web bash as root user</span>
     sudo docker compose exec web bin/docker/boot
     <span class="hljs-comment"># Run docker-compose down as root user</span>
     sudo docker compose down
   fi
 fi

 <span class="hljs-comment"># If operating system is macos</span>
 if [ <span class="hljs-string">"$DETECTED_OS"</span> = <span class="hljs-string">"darwin"</span> ]; then
   <span class="hljs-comment"># Set environment variables temporary</span>
   export CURRENT_GID=<span class="hljs-string">"0"</span>
   export CURRENT_UID=<span class="hljs-string">"0"</span>
   export NON_ROOT_USERNAME=<span class="hljs-string">"root"</span>
   export NON_ROOT_GROUPNAME=<span class="hljs-string">"root"</span>
   export OPERATING_SYSTEM=<span class="hljs-string">"mac"</span>

   <span class="hljs-comment"># Check if docker and docker compose are installed</span>
   if ! command -v docker &amp;&gt;/dev/null; then
     echo <span class="hljs-string">"Docker is not installed. Install docker : https://docs.docker.com/engine/install/"</span>
     exit <span class="hljs-number">0</span>
   fi

   <span class="hljs-comment"># Run docker-compose up</span>
   docker compose up -d --build
   <span class="hljs-comment"># Run docker-compose exec web bash</span>
   docker compose exec web bin/docker/boot
   <span class="hljs-comment"># Run docker-compose down</span>
   docker compose down
 fi
</code></pre>
<p> This one script is responsible to fetch user id and group id and set temporary environment variables.</p>
<p> This will start the container and then run <code>bin/docker/boot</code> inside the container. And after the container got exited, it run <code>docker compose down</code> to stop other containers as well.</p>
</li>
<li><p>💁 That's all.</p>
</li>
</ol>
<h4 id="heading-test-docker-setup">Test docker setup</h4>
<p>We have tested this docker setup in</p>
<ul>
<li><p>Windows [both Hyper-V and WSL2]</p>
</li>
<li><p>Linux</p>
</li>
<li><p>MacOS</p>
</li>
</ul>
<p>It works on all os without any issues.</p>
<p>For Windows, we have written a PowerShell script to support it as well.</p>
<pre><code class="lang-powershell"><span class="hljs-comment"># Set environment variables</span>
<span class="hljs-variable">$env:NON_ROOT_USERNAME</span> = <span class="hljs-string">"root"</span>;
<span class="hljs-variable">$env:NON_ROOT_GROUPNAME</span> = <span class="hljs-string">"root"</span>;
<span class="hljs-variable">$env:OPERATING_SYSTEM</span> = <span class="hljs-string">"windows"</span>;
<span class="hljs-variable">$env:PWD</span> = (<span class="hljs-built_in">Get-Location</span>).Path;
<span class="hljs-variable">$env:CURRENT_UID</span> = <span class="hljs-string">"0"</span>;
<span class="hljs-variable">$env:CURRENT_GID</span> = <span class="hljs-string">"0"</span>;

<span class="hljs-comment"># Check if docker is available</span>
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">Get-Command</span> <span class="hljs-literal">-Name</span> <span class="hljs-string">"docker"</span> <span class="hljs-literal">-ErrorAction</span> SilentlyContinue) {
    <span class="hljs-comment"># Run docker-compose up</span>
    docker compose up <span class="hljs-literal">-d</span> -<span class="hljs-literal">-build</span>
    <span class="hljs-comment"># Run docker-compose exec to boot the image</span>
    docker compose exec web bin/docker/boot
    <span class="hljs-comment"># Run docker-compose down</span>
    docker compose down
}
<span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">Write-Output</span> <span class="hljs-string">"Docker is not available. Follow this documentation to install docker: https://docs.docker.com/desktop/install/windows-install/"</span>
}
</code></pre>
<p>You can get more details in this PR - <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3913/">https://github.com/CircuitVerse/CircuitVerse/pull/3913/</a></p>
<h4 id="heading-rewrite-documentation">Rewrite Documentation</h4>
<p>Many changes were made to the project for improving the development experience. So it's very important to update the documentation as well.</p>
<p>We have written the documentation for Remote Development Platforms, as well as separate documentation for each operating system for setting up a docker-based environment + local installation.</p>
<p><strong>Additionally, working on the reviewed PRs. Making some changes on the PR to make it ready to merge.</strong></p>
<hr />
<p>That's all for this blog. If you liked this subscribe to the newsletter.</p>
<hr />
<p>🎉 Finally, my project <code>SwiftWave</code> has been published on GitHub.</p>
<p>SwiftWave is a self-hosted lightweight PaaS solution to deploy and manage your applications on any VPS without any hassle</p>
<p><strong>GitHub Link</strong> - <a target="_blank" href="https://github.com/swiftwave-org/swiftwave">https://github.com/swiftwave-org/swiftwave</a></p>
<p>If you like the initiative, star⭐ the project on GitHub.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Week 7 & 8 - CircuitVerse@GSOC'23]]></title><description><![CDATA[Finally, On July 14, I received this email about passing the midterm evaluation 🎉🎉.

You can check out the blog on the phase 1 report here: https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/
You should check other blogs here: https:/...]]></description><link>https://blog.tanmoysrt.xyz/week-7-8-circuitversegsoc23</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/week-7-8-circuitversegsoc23</guid><category><![CDATA[Remote Development]]></category><category><![CDATA[CircuitVerse]]></category><category><![CDATA[Gitpod]]></category><category><![CDATA[codespaces]]></category><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sun, 23 Jul 2023 08:42:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690095554993/69cc9372-29da-44d3-a909-ac2bda0652d9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Finally, On July 14, I received this email about passing the midterm evaluation 🎉🎉.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690095830442/f3a80b48-1b6c-4fdb-abfc-8f045c4de561.png" alt class="image--center mx-auto" /></p>
<p>You can check out the blog on the phase 1 report here: <a target="_blank" href="https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/">https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/</a></p>
<p>You should check other blogs here: <a target="_blank" href="https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/">https://blog.circuitverse.org</a>/</p>
<hr />
<p>These two weeks were full of debugging and much more learning. Finally, many issues were resolved in these weeks. So, let's get started.</p>
<hr />
<h3 id="heading-week-7">Week 7</h3>
<h4 id="heading-rbs-rails">RBS Rails</h4>
<p>Finally, the <code>rbs_rails</code> issue was resolved. Discussion thread <a target="_blank" href="https://github.com/pocke/rbs_rails/issues/260">here</a>.</p>
<p>The main issue was this -</p>
<p>The project previously uses <code>ActionMailer</code> for notifications. While migrating to <code>Noticed</code> Gem, we can't use the same table for notifications as we don't want to drop the data. So used <code>has_noticed_notifications</code> to override the model name to use <code>NoticedNotifications</code> the table.</p>
<p>There were some associations -</p>
<pre><code class="lang-ruby"> has_many <span class="hljs-symbol">:notifications</span>, <span class="hljs-symbol">as:</span> <span class="hljs-symbol">:notifiable</span>
</code></pre>
<p>This line was causing the issue of preventing <code>rbs_rails</code> gem from generating signatures for models.</p>
<p>After replacing the association with</p>
<pre><code class="lang-ruby">has_many <span class="hljs-symbol">:noticed_notifications</span>
</code></pre>
<p>All the issues are fixed!</p>
<p>Running this task <code>rbs_rails:generate_rbs_for_models</code> will generate the signature for models and the signature for dependencies as well.</p>
<p>After this, we can customize those signature files according to our need to add the custom functions we wrote in our models.</p>
<p>As we have previously set up <code>steep</code> gem to verify rbs signature, that speed up the process of writing rbs annotations.</p>
<p>If you haven't yet checked out RBS installation and CI integration with <code>steep</code>, you should check out this blog: <a target="_blank" href="https://tanmoy.online/week-4-circuitversegsoc23">https://tanmoy.online/week-4-circuitversegsoc23</a></p>
<p>The docs provided by <strong>RBS</strong> <a target="_blank" href="https://github.com/ruby/rbs/blob/master/docs/rbs_by_example.md">https://github.com/ruby/rbs/blob/master/docs/rbs_by_example.md</a> and this blog <a target="_blank" href="https://www.honeybadger.io/blog/ruby-rbs-type-annotation/">https://www.honeybadger.io/blog/ruby-rbs-type-annotation/</a> helps a lot to understand <strong>RBS</strong> easily.</p>
<p><mark>All PR: </mark> <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/issues/3792"><mark>https://github.com/CircuitVerse/CircuitVerse/issues/3792</mark></a></p>
<hr />
<h3 id="heading-week-8">Week 8</h3>
<p>This week's main target was to work on Remote Development Platform integrations.</p>
<p>Many changes have been made in the development environment over the last few weeks. So it was necessary to verify the Gitpod setup and integrate new features. As well as integrate Github Codespaces for Remote Development.</p>
<p>We also will look into the improvement of docker-based local development.</p>
<h4 id="heading-gitpod-remote-development">Gitpod Remote Development</h4>
<p>There is already gitpod setup in the project, but it has broken due to old version of Redis.</p>
<p>Universal APT repository hasn't the latest version of Redis, and sidekiq requires Redis &gt; v7.0. So we added the Redis repository and gpg key, and it was fixed.</p>
<pre><code class="lang-ruby">curl -fsSL <span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/packages.redis.io/gpg</span> <span class="hljs-params">| sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" |</span> sudo tee /etc/apt/sources.list.d/redis.list
apt-get update &amp;&amp; apt-get install redis
</code></pre>
<p>Now the GitPod is running, but it's missing all extensions.</p>
<p>After searching, I found that, due to Microsoft's latest Terms &amp; Conditions, external editors or open source VSCode alternatives like VsCodium or Theia IDE can't use Visual Studio Marketplace to fetch Extensions. So there comes <a target="_blank" href="https://open-vsx.org/">Open-VSX Registry</a>, which hosts and distributes VSCode Extension without restriction. For more details, read this blog <a target="_blank" href="https://www.gitpod.io/blog/open-vsx">https://www.gitpod.io/blog/open-vsx</a></p>
<p>So we move the extensions from Visual Studio Marketplace to Open-VSX Registry.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">vscode:</span>
  <span class="hljs-attr">extensions:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">dbaeumer.vscode-eslint</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">rebornix.ruby</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">castwide.solargraph</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">wingrunr21.vscode-ruby</span>
</code></pre>
<p>But some extensions like <code>Ruby debugger</code> &amp; <code>Ruby Rubocop Revived</code> The extension is still not available on <a target="_blank" href="https://open-vsx.org/">Open-VSX Registry</a>. So here is the workaround, we can generate <strong>VSIX</strong> file and provide the links.</p>
<p>We can generate VSIX files very quickly.</p>
<ul>
<li><p>Clone extension repository &amp; do <code>npm install</code></p>
</li>
<li><p>Install <strong>vsce</strong> plugin <code>npm install -g @vscode/vsce</code></p>
</li>
<li><p>Run <code>vsce package</code> to generate vsix file</p>
</li>
<li><p>Now, we can upload it somewhere and provide the URL in the extension list.</p>
</li>
</ul>
<p><mark>For more, check this PR: </mark> <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3892/files"><mark>https://github.com/CircuitVerse/CircuitVerse/pull/3892/</mark></a></p>
<h4 id="heading-github-codespaces-remote-development">Github CodeSpaces Remote Development</h4>
<p>Currently, the repository has no Github Codespace configuration so that we will introduce that.</p>
<p>Github Codespaces call this dev container, and we need the dev container configuration to be available to launch the project in the Github Codespaces environment.</p>
<p>We need a docker compose-based setup for our use case because we need Redis &amp; PostgreSQL as databases to start the project.</p>
<p>This documentation was beneficial to understand the configuration - <a target="_blank" href="https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers">https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers</a></p>
<ul>
<li><p>First, we create a Dockerfile, which will hold only the Environment to run our project.</p>
<pre><code class="lang-dockerfile">  <span class="hljs-keyword">FROM</span> ruby:<span class="hljs-number">3.2</span>.<span class="hljs-number">1</span>
  <span class="hljs-comment"># install dependencies</span>
  <span class="hljs-keyword">RUN</span><span class="bash"> apt-get update -qq &amp;&amp; apt-get install -y imagemagick shared-mime-info libvips &amp;&amp; apt-get clean</span>
  <span class="hljs-keyword">RUN</span><span class="bash"> curl -sL https://deb.nodesource.com/setup_14.x | bash \
   &amp;&amp; apt-get update &amp;&amp; apt-get install -y nodejs &amp;&amp; rm -rf /var/lib/apt/lists/* \
   &amp;&amp; curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
   &amp;&amp; <span class="hljs-built_in">echo</span> <span class="hljs-string">"deb https://dl.yarnpkg.com/debian/ stable main"</span> | tee /etc/apt/sources.list.d/yarn.list \
   &amp;&amp; apt-get update &amp;&amp; apt-get install -y yarn &amp;&amp; rm -rf /var/lib/apt/lists/* \
   &amp;&amp; apt-get update &amp;&amp; apt-get -y install cmake &amp;&amp; rm -rf /var/lib/apt/lists/* \
   &amp;&amp; apt-get update &amp;&amp; apt-get -y install netcat &amp;&amp; rm -rf /var/lib/apt/lists/</span>
</code></pre>
</li>
<li><p>Then we make a <code>docker-compose.yml</code> file that will contain the service's details</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">version:</span> <span class="hljs-string">"3.1"</span>
  <span class="hljs-attr">services:</span>
    <span class="hljs-attr">db:</span>
      <span class="hljs-attr">image:</span> <span class="hljs-string">postgres</span>
      <span class="hljs-attr">environment:</span>
        <span class="hljs-attr">POSTGRES_DB:</span> <span class="hljs-string">circuitverse_development</span>
        <span class="hljs-attr">POSTGRES_PASSWORD:</span> <span class="hljs-string">postgres</span>
    <span class="hljs-attr">web:</span>
      <span class="hljs-attr">build:</span>
        <span class="hljs-attr">context:</span> <span class="hljs-string">.</span>
        <span class="hljs-attr">dockerfile:</span> <span class="hljs-string">Dockerfile</span>
      <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span>
      <span class="hljs-attr">depends_on:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">db</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">redis</span>
      <span class="hljs-attr">environment:</span>
        <span class="hljs-attr">REDIS_URL:</span> <span class="hljs-string">"redis://redis:6379/0"</span>
        <span class="hljs-attr">CIRCUITVERSE_USE_SOLR:</span> <span class="hljs-string">"false"</span>
        <span class="hljs-attr">DOCKER_ENVIRONMENT:</span> <span class="hljs-string">'true'</span>
      <span class="hljs-attr">command:</span> <span class="hljs-string">sleep</span> <span class="hljs-string">infinity</span>
    <span class="hljs-attr">redis:</span>
      <span class="hljs-attr">image:</span> <span class="hljs-string">redis:7.0-alpine</span>
</code></pre>
</li>
<li><p>You can see the <code>web</code> service will start, and Github Codespace will attach to it. To prevent it from terminating, we used <code>sleep infinity</code> the command</p>
</li>
<li><p>Now, we require two scripts.</p>
<ul>
<li><p><strong>setup.sh</strong> -&gt; This script will be called when the container starts. Like database migration, dependency installation, etc.</p>
</li>
<li><p><strong>boot.sh</strong> -&gt; After the successful container setup, this script will start the application.</p>
</li>
</ul>
</li>
<li><p>Now, we can write <code>devcontainer.json</code> to complete the setup.</p>
<pre><code class="lang-json">  {
      <span class="hljs-attr">"hostRequirements"</span>: {
        <span class="hljs-attr">"cpus"</span>: <span class="hljs-number">4</span>
      },
      <span class="hljs-attr">"workspaceFolder"</span>: <span class="hljs-string">"/workspaces/CircuitVerse/"</span>,
      <span class="hljs-attr">"dockerComposeFile"</span>: <span class="hljs-string">"docker-compose.yml"</span>,
      <span class="hljs-attr">"service"</span>: <span class="hljs-string">"web"</span>,
      <span class="hljs-attr">"features"</span>: {
          <span class="hljs-attr">"ghcr.io/devcontainers/features/docker-outside-of-docker:1"</span>: {}
      },
      <span class="hljs-attr">"waitFor"</span>: <span class="hljs-string">"onCreateCommand"</span>,
      <span class="hljs-attr">"postCreateCommand"</span>: <span class="hljs-string">".devcontainer/setup.sh"</span>,
      <span class="hljs-attr">"postAttachCommand"</span>: {
        <span class="hljs-attr">"server"</span>: <span class="hljs-string">".devcontainer/boot.sh"</span>
      },
      <span class="hljs-attr">"customizations"</span>: {
        <span class="hljs-attr">"vscode"</span>: {
          <span class="hljs-attr">"extensions"</span>: [
              <span class="hljs-string">"dbaeumer.vscode-eslint"</span>,
              <span class="hljs-string">"LoranKloeze.ruby-rubocop-revived"</span>,
              <span class="hljs-string">"rebornix.Ruby"</span>,
              <span class="hljs-string">"wingrunr21.vscode-ruby"</span>,
              <span class="hljs-string">"KoichiSasada.vscode-rdbg"</span>
          ]
        }
      },

      <span class="hljs-attr">"forwardPorts"</span>: [<span class="hljs-number">3000</span>]
    }
</code></pre>
</li>
<li><p><code>service</code> Key takes the service name, which should the process will attach.</p>
</li>
<li><p><code>postAttachCommand</code> Key declares the script, which should will after the setup process.</p>
</li>
<li><p>We have also configured various extensions to provide convenience for developers. AS Microsoft powers Github Codespace, we have no issue using the extension from Visual Studio Code Marketplace.</p>
</li>
</ul>
<p>For more details, check this PR: <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3894/">https://github.com/CircuitVerse/CircuitVerse/pull/3894/</a></p>
<h4 id="heading-docker-based-development-environment">Docker-based development environment</h4>
<p>I have started working on this. Currently, the setup contains Docker configuration to run the app locally. But this is not suitable for faster development.</p>
<p>I have listed the issues here: <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/issues/3914">https://github.com/CircuitVerse/CircuitVerse/issues/3914</a></p>
<p>I am trying to rebuild the Docker configuration to build a local environment by using the same concept that Github Codespaces used.</p>
<p>Here is the draft PR: <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3913">https://github.com/CircuitVerse/CircuitVerse/pull/3913</a></p>
<p>In the next blog, I will explain these stuffs in detail.</p>
<hr />
<p>🏂 Thank you for getting it a read</p>
]]></content:encoded></item><item><title><![CDATA[Week 6 - CircuitVerse@GSOC'23]]></title><description><![CDATA[At the start, this week's main focus was completing the RBS integration. But that does not go well due to having issues with rbs_rails Gem. So I raised PR in rbs_rails the gem repository about the issue to get some hints from the maintainers.
You can...]]></description><link>https://blog.tanmoysrt.xyz/week-6-circuitversegsoc23</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/week-6-circuitversegsoc23</guid><category><![CDATA[CircuitVerse]]></category><category><![CDATA[gsoc2023]]></category><category><![CDATA[Rails]]></category><category><![CDATA[selenium]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sun, 23 Jul 2023 06:55:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690095174036/faef3562-c153-4886-b6af-ea5619b91eef.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>At the start, this week's main focus was completing the RBS integration. But that does not go well due to having issues with <code>rbs_rails</code> Gem. So I raised PR in <code>rbs_rails</code> the gem repository about the issue to get some hints from the maintainers.</p>
<p>You can check out the discussion thread here -&gt; <a target="_blank" href="https://github.com/pocke/rbs_rails/issues/260">https://github.com/pocke/rbs_rails/issues/260</a></p>
<p>As this will take a long time to resolve, I moved to the following topic: writing missing integration test cases. It was the first time I listened to integration testing; I only knew about it before that. But it's crazy and can always help keep the UI flow unchanged regardless of changes.</p>
<p>As per the planning, I should cover these workflows by integration testing</p>
<ul>
<li><p>Profile Management</p>
</li>
<li><p>Group Management</p>
</li>
<li><p>Assignment management</p>
</li>
<li><p>Project management</p>
</li>
</ul>
<p>These tasks were pretty straightforward, like automating manual testing. Rails use <a target="_blank" href="https://github.com/teamcapybara/capybara">capybara</a> gem to execute integration testing with the Selenium web driver.</p>
<p>During writing test cases, one problem is that some UI fields like bootstrap-select require one to type and press enter after each entry to take effect. We can achieve this by using <code>send_keys</code> .</p>
<p>To make it easy, we build a function to wrap things</p>
<pre><code class="lang-ruby">  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fill_in_input</span><span class="hljs-params">(input, <span class="hljs-symbol">with:</span>)</span></span>
    find(input).send_keys with
  <span class="hljs-keyword">end</span>
</code></pre>
<p>Then, we can insert some text in the input and press <code>enter</code></p>
<pre><code class="lang-ruby">fill_in_input <span class="hljs-string">"#input_id"</span>, <span class="hljs-symbol">with:</span> <span class="hljs-string">"test@test.com"</span>
fill_in_input <span class="hljs-string">"#input_id"</span>, <span class="hljs-symbol">with:</span> <span class="hljs-symbol">:enter</span>
</code></pre>
<p>You can check out the PR's here -&gt; <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/issues/3854">https://github.com/CircuitVerse/CircuitVerse/issues/3854</a></p>
<hr />
<p>GSOC Midterm evaluation is approaching soon. We need to work on wrapping all the work and prepare a blog about all the progress in phase 1 of GSOC.</p>
<p>The official blog is published here -&gt; <a target="_blank" href="https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/">https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/</a></p>
<p>You can find out all the blogs of CircuitVerse here -&gt; <a target="_blank" href="https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/">https://blog.circuitverse.org/</a></p>
<hr />
<p>Thank you for giving it a read.</p>
]]></content:encoded></item><item><title><![CDATA[Week 5 - CircuitVerse@GSOC'23]]></title><description><![CDATA[This week was more on learning rather than coding.
The main objectives of this week were

Learn RBS to start working on it

Generate code coverage report and write the missing unit-tests

Split Solargraph PR to small PRs for better review



Learn RB...]]></description><link>https://blog.tanmoysrt.xyz/week-5-circuitversegsoc23</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/week-5-circuitversegsoc23</guid><category><![CDATA[Rails]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[unit testing]]></category><category><![CDATA[gsoc]]></category><category><![CDATA[CircuitVerse]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sat, 01 Jul 2023 09:28:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1688199155710/c390939d-82f6-49eb-9236-b6e9fc1d9520.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This week was more on learning rather than coding.</p>
<p>The main objectives of this week were</p>
<ul>
<li><p>Learn RBS to start working on it</p>
</li>
<li><p>Generate code coverage report and write the missing unit-tests</p>
</li>
<li><p>Split Solargraph PR to small PRs for better review</p>
</li>
</ul>
<hr />
<h4 id="heading-learn-rbs-to-start-working-on-it">Learn RBS to start working on it</h4>
<p>At first, I thought RBS was pretty straightforward, and I needed to write the type signature of defined functions. But that's not enough.</p>
<p>We know Rails use the metaprogramming concept hugely. So it's essential to have some extra type signatures in ActiveModel, ApplicationRecord, and Controllers.</p>
<p>But, I found a much easier way for this at last.</p>
<p>We can generate an untyped version of the <strong>*.rbs</strong> file for an <strong>*rb</strong> file</p>
<pre><code class="lang-yaml"><span class="hljs-string">bundle</span> <span class="hljs-string">exec</span> <span class="hljs-string">rbs</span> <span class="hljs-string">prototype</span> <span class="hljs-string">rb</span> <span class="hljs-string">&lt;ruby_file_path&gt;</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">&lt;output_rbs_file_path&gt;</span>
</code></pre>
<p>After the <strong>*rbs</strong> file is generated, we can edit the argument type and return type to make it works.</p>
<p>In the coming weeks, I think to complete writing <strong>rbs</strong> annotations for the codebase.</p>
<hr />
<h4 id="heading-generate-code-coverage-report-and-write-the-missing-unit-tests">Generate code coverage report and write the missing unit-tests</h4>
<p>As I was learning RBS, I focused on making some active contributions. So picked the next task -&gt; <code>writing unit test for missing code coverage</code>.</p>
<p>I need first to analyze which unit-test cases are missing. I use <code>simplecov</code> with <code>HTMLFormatter</code> which generates coverage reports as HTML.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688201441617/93587e96-63b0-4f1b-b274-c57134fc251f.png" alt class="image--center mx-auto" /></p>
<p>From the report, It's nice that most of the code has unit tests, and a few codes have only missing tests.</p>
<p>Created this issue to have a track -&gt; <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/issues/3817">CircuitVerse/CircuitVerse#3817</a></p>
<p>This issue has all the linked PRs</p>
<p>This <strong>rspec-rails</strong> gem has this great documentation <a target="_blank" href="https://rspec.info/features/6-0/rspec-rails/controller-specs/">https://rspec.info/features/6-0/rspec-rails/controller-specs/</a>, and it makes the task easier.</p>
<hr />
<h4 id="heading-split-solargraph-pr-to-small-prs-for-better-review">Split Solargraph PR to small PRs for better review</h4>
<p>Last week, I finalized <strong>solargraph-integration</strong> PR <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3766">CircuitVerse/CircuitVerse#3766</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688202195465/cf72e74c-3165-417e-b58a-5d3f94d10bb7.png" alt class="image--center mx-auto" /></p>
<p>See the changes in the PR, it's hard to review this large PR.</p>
<p>So my mentor suggested splitting this PR into smaller PRs. The main problem with smaller PRs was - We usually do a checkout from the master/main branch to do the changes. But in this case, I need the previous PR's file merged before moving. It's not practical as maintainers will do reviews in their free time and there will be a long waiting time. So found a better way.</p>
<ul>
<li><p>Checkout from master/main branch to branch_A</p>
</li>
<li><p>Do the changes in branch_A and raise Pull Request for changes in branch_A</p>
</li>
<li><p>Now, Checkout from branch_A to branch_B</p>
</li>
<li><p>Do the changes in branch_B and raise Pull Request for changes in branch_B</p>
</li>
<li><p>Do this as many times as we need .......</p>
</li>
<li><p>After merging PR_A, we need to update branch_B against the master/main branch, which will make PR_B small. Do this until all PRs merge is completed.</p>
</li>
</ul>
<blockquote>
<p>We need to make sure that the PR's merged in the same order at the time of raising PR, else merge conflict can be arised</p>
</blockquote>
<p>Here is the Issue, where I have listed all the PRs - <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/issues/3761">CircuitVerse/CircuitVerse#3761</a></p>
<hr />
<p>That's all for this week. Subscribe to the newsletter for more updates.</p>
]]></content:encoded></item><item><title><![CDATA[Week 4 - CircuitVerse@GSOC'23]]></title><description><![CDATA[This week was interesting and frustrating at the same time. The maximum time went to explore solutions and resolving the issues with specific library packages. This time everything does not go as planned.
The scheduled task for this week was

Write R...]]></description><link>https://blog.tanmoysrt.xyz/week-4-circuitversegsoc23</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/week-4-circuitversegsoc23</guid><category><![CDATA[Ruby]]></category><category><![CDATA[CircuitVerse]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[undercover]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sat, 24 Jun 2023 09:56:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1687596971403/2dce112e-b0da-4048-9edf-45b6c673212a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This week was interesting and frustrating at the same time. The maximum time went to explore solutions and resolving the issues with specific library packages. This time everything does not go as planned.</p>
<p>The scheduled task for this week was</p>
<ul>
<li>Write RBS Annotations for the codebase</li>
</ul>
<h3 id="heading-rbs">RBS</h3>
<p><strong>What is RBS?</strong></p>
<p>RBS is a type annotation system introduced in the Ruby programming language. Its purpose is to bring static typing capabilities to Ruby code. We can verify the type signature by using various tools like [steep, rbs, etc.]</p>
<p>RBS is released officially by Ruby.</p>
<p><strong>Interesting Features</strong></p>
<ul>
<li><p><em>Type Safety:</em> RBS helps catch type-related errors early, improving code reliability.</p>
</li>
<li><p><em>Tooling Support:</em> Static type information enables advanced code editors to offer autocompletion and accurate error detection, enhancing developer productivity.</p>
</li>
<li><p><em>Documentation and Readability:</em> RBS annotations serve as documentation, making code easier to understand and maintain.</p>
</li>
</ul>
<p><strong>Setup</strong></p>
<ul>
<li><p>Install <code>rbs_rails</code> gem</p>
<pre><code class="lang-bash">  gem install rbs_rails
</code></pre>
</li>
<li><p>Generate tasks</p>
<pre><code class="lang-bash">  bin/rails g rbs_rails:install
</code></pre>
</li>
<li><p>Run this to generate the rbs collection configuration file</p>
<pre><code class="lang-bash">  bundle <span class="hljs-built_in">exec</span> rbs collection init
</code></pre>
</li>
<li><p>Now simply run this to download the required gem's rbs file</p>
<pre><code class="lang-bash">  bundle <span class="hljs-built_in">exec</span> rbs collection install
</code></pre>
</li>
<li><p>We are going to use <code>steep</code> gem to type checking</p>
</li>
<li><p>So, install <code>steep</code> gem</p>
<pre><code class="lang-bash">  bundle install steep
</code></pre>
</li>
<li><p>Create <code>Steepfile</code> with this configuration</p>
<pre><code class="lang-bash">  target :app <span class="hljs-keyword">do</span>
    signature <span class="hljs-string">"sig"</span>
  end
</code></pre>
</li>
<li><p>As per the configuration, it will check sig folder for our writer rbs annotation files for our codebase</p>
</li>
</ul>
<p><strong>Issues</strong></p>
<p>But one problem with RBS is -&gt; As it's fairly new to the market, there is not much support for RBS in all the libraries. So we face various issues regarding that.</p>
<p>In our case, while using <code>rbs validate</code> it was throwing <code>RBS::DuplicatedMethodDefinitionError</code> due to conflicting rbs code of <code>meta-tags</code> and <code>activesupport</code> gem.</p>
<p>After searching for various solutions and taking suggestions from the maintainer, the final solution to fix the issue was -</p>
<ul>
<li><p>Add <code>meta-tags</code> gem to ignore the list of rbs collection configurations like</p>
<pre><code class="lang-bash">  gems:
    <span class="hljs-comment"># Skip loading rbs gem's RBS.</span>
    <span class="hljs-comment"># It's unnecessary if you don't use rbs as a library.</span>
    - name: rbs
      ignore: <span class="hljs-literal">true</span>
    - name: steep
      ignore: <span class="hljs-literal">true</span>
</code></pre>
</li>
<li><p>Copy the rbs file of <code>meta-tags</code> gem</p>
</li>
<li><p>Modify them to remove duplicate definition issue</p>
</li>
<li><p>And then copy-paste those files in <code>sig/vendor/meta-tags</code> folder</p>
</li>
</ul>
<p><strong>References -</strong></p>
<p>Discussion Thread for the issue - <a target="_blank" href="https://github.com/ruby/rbs/issues/1359">https://github.com/ruby/rbs/issues/1359</a></p>
<p>PR - <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3807/">https://github.com/CircuitVerse/CircuitVerse/pull/3807/</a></p>
<h3 id="heading-undercover-ci">Undercover CI</h3>
<p>Undercover is a great tool to analyze untested code of a commit and do PR reviews.</p>
<p>SimpleCov is mainly used to generate the test details and undercover analyze the generated Lcov file.</p>
<p><strong>Setup SimpleCov to generate the Lcov file</strong></p>
<ul>
<li><p>Install <code>simplecov</code> and <code>simplecov-lcov</code> gem to <code>:test</code> group</p>
</li>
<li><p>In the <code>config/environments/test.rb</code> file, paste this configuration file at the top</p>
<pre><code class="lang-ruby">  <span class="hljs-keyword">require</span> <span class="hljs-string">"simplecov"</span>
  <span class="hljs-keyword">require</span> <span class="hljs-string">"simplecov-lcov"</span>
  SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = <span class="hljs-literal">true</span>
  SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
  SimpleCov.start <span class="hljs-keyword">do</span>
    add_filter(<span class="hljs-regexp">/^\/spec\//</span>) <span class="hljs-comment"># For RSpec, use `test` for MiniTest</span>
    enable_coverage(<span class="hljs-symbol">:branch</span>)
  <span class="hljs-keyword">end</span>
</code></pre>
</li>
<li><p>Now we need to load all the code beforehand for this analysis</p>
</li>
<li><p>So, mark <code>config.eager_load</code> = true in configuration of test environment</p>
</li>
<li><p>Now when we run our test suite, it will generate lcov file under <code>coverage/lcov/&lt;project_name&gt;.lcov</code> file.</p>
</li>
</ul>
<p><strong>Now, We need to setup undercover CI for PR review</strong></p>
<p>The first and easier option is to use <a target="_blank" href="https://undercover-ci.com/">https://undercover-ci.com/</a> which has simple steps for installation. But the issue here is , it's paid for organization</p>
<p>So,we keep searching and found a opensource project <a target="_blank" href="https://github.com/aki77/undercover-checkstyle">undercover-checkstyle</a> which can review the PR by using <code>undercover</code> CLI tool and use <a target="_blank" href="https://github.com/reviewdog/reviewdog">reviewdog</a> to do the PR Review</p>
<p>For this, add <code>undercover-checkstyle</code> gem under <code>:test</code> group in Gemfile</p>
<p>In the CI workflow add this configuration</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">aki77/delete-pr-comments-action@v1</span>
  <span class="hljs-attr">with:</span>
   <span class="hljs-attr">token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
   <span class="hljs-attr">bodyContains:</span> <span class="hljs-string">"[undercover]"</span>
   <span class="hljs-attr">noReply:</span> <span class="hljs-string">"true"</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">reviewdog</span>
  <span class="hljs-attr">env:</span>
    <span class="hljs-attr">REVIEWDOG_GITHUB_API_TOKEN:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.github_token</span> <span class="hljs-string">}}</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">|
    git fetch --no-tags
    reviewdog -reporter=github-pr-review -runners=undercover --fail-on-error</span>
</code></pre>
<p>After the setup, it will provide a review of any PR.</p>
<p>Just for example, the <code>github-actions bot</code> will give a review like this. <em>This will also delete previous comments to make the PR Review clean.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687600399601/68dd1e9b-5aac-4b1d-82a3-14fd4b049ff5.png" alt class="image--center mx-auto" /></p>
<p>PR - <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3812">CircuitVerse/CircuitVerse#3812</a> <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3818">CircuitVerse/CircuitVerse#3818</a></p>
<hr />
<p>That's all for this week. Subscribe to the newsletter for more updates.</p>
]]></content:encoded></item><item><title><![CDATA[Week 3 - CircuitVerse@GSOC'23]]></title><description><![CDATA[This week was a little bit hectic, and the integrations were a little bit error-prone. However, I fixed all the issues by following the GitHub Forum and Github Issues discussion of particular library/software.
The main tasks of this week -

Integrate...]]></description><link>https://blog.tanmoysrt.xyz/week-3-circuitversegsoc23</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/week-3-circuitversegsoc23</guid><category><![CDATA[gsoc2023]]></category><category><![CDATA[CircuitVerse]]></category><category><![CDATA[Ruby]]></category><category><![CDATA[vite]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sat, 17 Jun 2023 10:20:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686986087112/0ce313f9-d98a-4308-80ca-976705d43616.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This week was a little bit hectic, and the integrations were a little bit error-prone. However, I fixed all the issues by following the GitHub Forum and Github Issues discussion of particular library/software.</p>
<h3 id="heading-the-main-tasks-of-this-week">The main tasks of this week -</h3>
<ul>
<li><p>Integrate Vite Rails</p>
</li>
<li><p>Initialization of RBS</p>
</li>
</ul>
<h3 id="heading-integrate-vite-rails">Integrate Vite Rails</h3>
<p><strong>Purpose -</strong> We are mainly integrating Vite Rails and will move Simulator assets to Vite. Currently, CircuitVerse uses sprockets and esbuild to pack javascript files and serve through the asset pipeline.</p>
<p><em>So, What's the issue with the current setup?</em></p>
<p>The issue is mainly with development experience. When the developer modifies any Javascript / SCSS files, esbuild rebuilds the assets, and the user needs to refresh the page to see the changes, which is very time-consuming.</p>
<p>When Vite comes into the picture, It does not build the assets to a single *.js or *.css file.</p>
<p>The main features of Vite</p>
<ul>
<li><p><strong>Lazy Loading:</strong> It does not bundle all the javascript in one single file and then serve. It simply sends one entry point file to the browser and will recursively load all the dependency javascript and compiled SCSS files to the browser.</p>
</li>
<li><p><strong>Hot Reload:</strong> Whenever there are any changes in javascript or SCSS files, the Vite client will manage to update that in the browser without refreshing the page. The entire page will be reloaded automatically if the 'Hot Reload' feature can't reflect any browser changes.</p>
</li>
</ul>
<p>The end of the story is it will make the development experience much better than the previous setup.</p>
<p><strong>Integration -</strong></p>
<ol>
<li><p>Install <code>ruby_rails</code> gem</p>
<pre><code class="lang-bash"> bundle install vite_rails
</code></pre>
</li>
<li><p>Run this to generate the configuration files</p>
<pre><code class="lang-bash"> bundle <span class="hljs-built_in">exec</span> vite install
</code></pre>
</li>
<li><p>In <code>config/vite.json</code> you can put the Vite dev server's configuration</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"all"</span>: {
     <span class="hljs-attr">"sourceCodeDir"</span>: <span class="hljs-string">"app/javascript"</span>,
     <span class="hljs-attr">"watchAdditionalPaths"</span>: []
   },
   <span class="hljs-attr">"development"</span>: {
     <span class="hljs-attr">"autoBuild"</span>: <span class="hljs-literal">true</span>,
     <span class="hljs-attr">"publicOutputDir"</span>: <span class="hljs-string">"vite-dev"</span>,
     <span class="hljs-attr">"port"</span>: <span class="hljs-number">3036</span>
   },
   <span class="hljs-attr">"test"</span>: {
     <span class="hljs-attr">"autoBuild"</span>: <span class="hljs-literal">true</span>,
     <span class="hljs-attr">"publicOutputDir"</span>: <span class="hljs-string">"vite-test"</span>,
     <span class="hljs-attr">"port"</span>: <span class="hljs-number">3037</span>
   }
 }
</code></pre>
</li>
<li><p>In the default config, it chooses <code>app/javascript</code> for entry points</p>
</li>
<li><p>We remove the <code>simulator.js</code> from esbuild and move to Vite by dragging the file to this directory</p>
</li>
<li><p>Now in the *.erb files, we need to replace <code>javascript_tag</code> with <code>vite_javascript_tag</code></p>
<pre><code class="lang-ruby"> &lt;%= vite_javascript_tag <span class="hljs-string">"simulator"</span> %&gt;
</code></pre>
</li>
<li><p>Here is a catch, Vite loads this javascript and SCSS asynchronously, so the other scripts may fail.</p>
<p> Assume you have some inline scripts required <code>jQuery</code>, but as Vite loads them asynchronously, the inline scripts will be executed without <code>jQuery</code> and throw a bunch of errors.</p>
<p> <strong><em>We can resolve the issue by following this.</em></strong></p>
<ol>
<li><p>vite_javascript_tag adds type=module and async tag to Script</p>
</li>
<li><p>After <code>async</code> tags execution <code>defer</code> tags will be executed.</p>
</li>
<li><p>After all assets are loaded, the <code>load</code> event will be fired.</p>
</li>
<li><p>So the flow will be like</p>
<ol>
<li><p>Put vite_javascript_tag at the start or head of the HTML</p>
</li>
<li><p>Wherever you have <code>&lt;script src="https://example.com/example.js"&gt;</code> use <code>defer</code> in it</p>
<pre><code class="lang-xml"> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://example.com/example.js"</span> <span class="hljs-attr">defer</span>&gt;</span>
</code></pre>
</li>
<li><p>In the usual Script, add the EventListener for <code>load</code> event</p>
<pre><code class="lang-xml"> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
 <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"load"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-comment">// Your code goes here</span>
 })
 </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
</li>
<li><p>That's all</p>
</li>
</ol>
</li>
</ol>
</li>
<li><p>Then, we need to add <code>Vite</code> dev server in <code>Procfile.dev</code> to run it with Foreman</p>
<pre><code class="lang-apache"> <span class="hljs-attribute">vite</span>: bin/vite dev
</code></pre>
</li>
<li><p>Now we can access the UI as usual, and Vite will take care of asset delivery and Hot Reloads.</p>
</li>
</ol>
<p><strong><mark>PR - </mark></strong> <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3777"><mark>https://github.com/CircuitVerse/CircuitVerse/pull/3777</mark></a></p>
<hr />
<h3 id="heading-initialization-of-rbs">Initialization of RBS</h3>
<p><strong>Purpose -</strong> We know Ruby is a dynamically typed language. So type checking stuff is not available, which can lead to inconsistency in the codebase and create bugs by mistake. Ruby finally came up with RBS [Type Signature for Ruby], which adds support for static type checking. Which helps to solve two issues</p>
<ul>
<li><p>a) Static Type Checking Validation</p>
</li>
<li><p>b) LSP Support</p>
<ul>
<li>Some LSP like <code>solargraph</code> added support to provide Language Autocompletion based on the RBS files.</li>
</ul>
</li>
</ul>
<p><strong>Integration -</strong></p>
<ol>
<li><p>For Rails, we install <code>rbs_rails</code> better support for Rails</p>
<pre><code class="lang-bash"> bundle install rbs_rails
</code></pre>
</li>
<li><p>Add <code>.gem_rbs_collection</code> in the <code>.gitignore</code></p>
</li>
<li><p>Run <code>rbs collection init</code> to generate config files</p>
</li>
<li><p>Run <code>rbs collection install</code> to download rbs files of our Gem</p>
</li>
<li><p>We can use <code>steep</code> for static type checking</p>
</li>
<li><p>So add <code>steep</code> gem</p>
<pre><code class="lang-bash"> bundle install steep
</code></pre>
</li>
<li><p>Create <code>Steepfile</code> for its configuration</p>
<pre><code class="lang-apache"> <span class="hljs-attribute">target</span> :app do
   <span class="hljs-attribute">signature</span> <span class="hljs-string">"sig"</span>
   <span class="hljs-attribute">check</span> <span class="hljs-string">"app"</span>
 <span class="hljs-attribute">end</span>
</code></pre>
</li>
<li><p>That's all</p>
</li>
</ol>
<p>But, there is some issue with RBS</p>
<ol>
<li>like <code>ActiveSupport</code> and <code>meta-tags</code> have some overlapped <code>rbs</code> for <code>Object</code> class, so when we run <code>rbs validate</code> , it will give an error for duplicate definitions. Currently managed it by manually deleting the duplicate rbs annotation.</li>
</ol>
<p><strong><mark>PR -</mark></strong> <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3807"><mark>https://github.com/CircuitVerse/CircuitVerse/pull/3807</mark></a></p>
<p>In the coming week, I hope to finish this RBS stuff and fix the issue described before.</p>
<p>Thanks a lot for reading this blog. If you like to know more about my GSOC journey and want to explore more in development, subscribe to the newsletter.</p>
]]></content:encoded></item><item><title><![CDATA[Week 1 & 2- CircuitVerse@GSOC'23]]></title><description><![CDATA[Community Bonding Period
This was a long time between getting the selection mail and the coding period. It allows me to learn more about some toolkits and libraries in detail required for this project. During this period, we have a couple of online d...]]></description><link>https://blog.tanmoysrt.xyz/week-1-2-circuitversegsoc23</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/week-1-2-circuitversegsoc23</guid><category><![CDATA[gsoc2023]]></category><category><![CDATA[CircuitVerse]]></category><category><![CDATA[gsoc]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Fri, 09 Jun 2023 17:31:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686221149365/02a657f8-c231-41f4-880a-d17a1fc1bd17.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-community-bonding-period">Community Bonding Period</h3>
<p>This was a long time between getting the selection mail and the coding period. It allows me to learn more about some toolkits and libraries in detail required for this project. During this period, we have a couple of online discussions with the mentors to discuss the timeline [if any changes are required] and some topics of the project on which I will work in the coming weeks.</p>
<p><em>Officially the coding period begins on 29th May 2023</em></p>
<hr />
<h3 id="heading-the-main-goal-of-these-two-weeks">The main goal of these two weeks</h3>
<ul>
<li><p>Integrate Ruby Debugger Support</p>
</li>
<li><p>Integrate Solargraph LSP</p>
</li>
</ul>
<p>And both the integrations should be compatible with the local setup as well as the docker container-based development setup</p>
<hr />
<h3 id="heading-integrate-ruby-debugger">Integrate Ruby Debugger</h3>
<p><strong>Purpose -</strong> Currently this project has <code>byebug</code> gem for debugging purposes. Ruby has released its official debugger <code>debug</code> gem which works with various IDEs flawlessly with the visual interface which makes it very easy for developers and contributors to debug the application.</p>
<p><strong>Implementation -</strong></p>
<p>Install <a target="_blank" href="https://github.com/ruby/debug"><code>debug</code></a> gem in the project.</p>
<p>Now, we can debug our application with VSCode with local installation by running this command</p>
<pre><code class="lang-bash"> bundle <span class="hljs-built_in">exec</span> rdbg --open --nonstop --<span class="hljs-built_in">command</span> -- bundle <span class="hljs-built_in">exec</span> rails server -p 3000This will start the rails server and will attach the debugger with that process.
</code></pre>
<p><strong>For debugging with VSCode</strong>, install the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg">vscode-rdbg</a> extension from marketplace.</p>
<blockquote>
<p>Use v1.0.0 of this extension as the v2.0.0 version has some bugs. The bug has been fixed but the new version has yet not released</p>
</blockquote>
<p>Now, in the VSCode we need to provide the settings for the debugger.</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.1.0"</span>,
    <span class="hljs-attr">"configurations"</span>: [
        {
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"rdbg"</span>,
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Attach Debugger"</span>,
            <span class="hljs-attr">"request"</span>: <span class="hljs-string">"attach"</span>
        }
    ]
}
</code></pre>
<p>Now, we can attach to this and set breakpoints and debug the application.</p>
<p>We can also, debug the application with Chrome by providing <code>--open=chrome</code> option.</p>
<pre><code class="lang-bash">  bundle <span class="hljs-built_in">exec</span> rdbg -n --open=chrome --<span class="hljs-built_in">command</span> -- bundle <span class="hljs-built_in">exec</span> rails server -p 3000
</code></pre>
<p>Now, we have two choices for debugging - any <strong>IDE</strong> or <strong>Chrome</strong></p>
<p>To make it convenient for end-user,</p>
<ul>
<li><p>Created two files <code>Procfile.dev</code> for IDEs and <code>Procfile.chrome.dev</code> for chrome-based debugging</p>
</li>
<li><p>In the <code>/bin/dev</code> file added <code>chrome_debug</code> flag check. If user provides <code>chrome_debug</code> flag while running the command it will open chrome for debugging else it will allow IDE to attach to the debugger</p>
</li>
<li><p><code>/bin/dev</code> for default mode and <code>/bin/dev chrome_debug</code> for chrome-based debugging</p>
</li>
</ul>
<p><strong>Make it compatible with a docker-based setup :</strong></p>
<p>To accomplish this, we use the TCP-based remote debugging feature of <code>debug</code> gem.</p>
<p>In the <code>dev/docker_run</code> we put the command for socket-based debugging by providing host and port [3001]</p>
<pre><code class="lang-bash">bundle <span class="hljs-built_in">exec</span> rdbg  --nonstop --open --host 0.0.0.0 --port 3001 -c -- bundle <span class="hljs-built_in">exec</span> rails s -p 3000 -b <span class="hljs-string">'0.0.0.0'</span>
</code></pre>
<p>So, now the debugger client can attach to the 3001 port and debug the application.</p>
<p>Now we need to expose the port by specifying the port mapping in the <em>docker-compose.yml</em> file</p>
<pre><code class="lang-yaml"><span class="hljs-attr">ports:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">"3001:3001"</span>
</code></pre>
<p>But, in the VSCode we need to add separate config for the debugger client to attach to tcp based remote debugging server</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"type"</span>: <span class="hljs-string">"rdbg"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"(Docker) Attach debugger [:3001]"</span>,
  <span class="hljs-attr">"request"</span>: <span class="hljs-string">"attach"</span>,
  <span class="hljs-attr">"debugPort"</span>: <span class="hljs-string">"localhost:3001"</span>,
  <span class="hljs-attr">"showProtocolLog"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"localfsMap"</span>: <span class="hljs-string">"/circuitverse:${workspaceFolder}"</span>
}
</code></pre>
<p>🏂 Now this setup will allow debugging with VSCode or Chrome or Any other supported IDE with both local and Docker-based installation</p>
<p><strong>Issues &amp; Fixes -</strong></p>
<p>During the integration, initially, it was failing as the Puma was configured to run multiple web workers at a time. For this, the debugger server process also got multiplied and want to start multiple processes either on the same Unix port or the same TCP port and the processes failed.</p>
<p>To resolve the issue, we change the default value of <code>WEB_CONCURRENCY</code> in <code>/config/puma.rb</code> to 0 for the development environment</p>
<p>This fixes the problem.</p>
<p><strong><mark>Pull Request -</mark></strong> <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3760"><mark>https://github.com/CircuitVerse/CircuitVerse/pull/3760</mark></a></p>
<hr />
<h3 id="heading-integrate-solargraph-lsp">Integrate Solargraph LSP</h3>
<p><strong>Purpose -</strong> Currently, in this project, no Language Server is configured so we can't utilise autocomplete feature of IDE. The project is built on the Ruby on Rails framework which has used metaprogramming too much. So by default, the LSPs can't provide autocomplete or suggestions. So we have planned to integrate Solargraph as a Language Server to enable autocompletion and make it convenient for other contributors while working on this project.</p>
<p><strong>Implementation -</strong></p>
<p>The main gem for this solargraph LSP is <a target="_blank" href="https://github.com/castwide/solargraph"><code>solargraph</code></a> .</p>
<p>We need to write the yard docs for the codebase to enable auto-completion. But in Rails, there are ActiveRecord models and many abstract classes which will make it complex to write yard docs for those. So, there is another gem [kind of extension of <code>solargraph</code> gem] called <a target="_blank" href="https://github.com/iftheshoefritz/solargraph-rails"><code>solargraph-rails</code></a> which allows us to easily add yard docs for the ActiveRecord models.</p>
<p>We can learn how to write the yard docs from this <a target="_blank" href="https://rubydoc.info/gems/yard/file/docs/GettingStarted.md">documentation</a>.</p>
<p>After completion of writing yard docs, we can enable this for many IDEs by <a target="_blank" href="https://github.com/castwide/solargraph#using-solargraph">the following guide</a></p>
<p>In VSCode, we can install <code>ruby solargraph</code> extension and got the autocompletion instantly.</p>
<p>For NeoVim, check out <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/issues/3776#issuecomment-1579491735">this discussion thread</a></p>
<p>For Sublime Text Editor, check out <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/issues/3776#issuecomment-1579472035">this discussion thread</a></p>
<p>For local setup, this works without any issues.</p>
<p><strong>But now we need to make it compatible with a docker-based setup.</strong></p>
<p>Here we utilize the TCP socket-based LSP server feature. Inside the container, we start the solargraph LSP server at port 3002 and expose it to the host</p>
<pre><code class="lang-json">solargraph socket --host=<span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span> --port=<span class="hljs-number">3002</span>
</code></pre>
<p>Now, in the VSCode or other IDEs, we can configure to use this external solargraph server.</p>
<p>But here an issue comes, The plugin of IDE or Code Editor sends the current path of the file to the LSP server. The container and the current host directory is different, so the LSP fails to resolve and provide autocompletion.</p>
<p>To resolve this issue, I take this approach.</p>
<ul>
<li><p>Pass the current directory to the container by using the environment variable</p>
<ul>
<li>In docker-compose, we can use <code>$PWD</code> to know the current directory path</li>
</ul>
</li>
<li><p>In the container, create a symlink at <code>$PWD</code> which points to <code>/circuitverse/</code> in the container</p>
</li>
</ul>
<p>Visual Representation</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686228207234/4ad7d750-f0c9-43fd-8956-531954c9c1d2.png" alt class="image--center mx-auto" /></p>
<p>Thus the path inside the container resolves and the solargraph provides the autocompletion without any issue.</p>
<p>Checkout the PR, to know more about this approach</p>
<p><strong><mark>Pull Request -</mark></strong> <a target="_blank" href="https://github.com/CircuitVerse/CircuitVerse/pull/3766"><mark>https://github.com/CircuitVerse/CircuitVerse/pull/3766</mark></a></p>
]]></content:encoded></item><item><title><![CDATA[Redis VS Memcached for cache]]></title><description><![CDATA[Redis :
Redis is an open-source, in-memory data structure store, used as a database, cache, and message broker.
Memcached:
Memcached is a distributed, high-performance, in-memory caching system. It is used to temporarily store and serve frequently re...]]></description><link>https://blog.tanmoysrt.xyz/redis-vs-memcached-for-cache</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/redis-vs-memcached-for-cache</guid><category><![CDATA[webdev]]></category><category><![CDATA[backend]]></category><category><![CDATA[cache]]></category><category><![CDATA[Redis]]></category><category><![CDATA[memcached]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Thu, 02 Feb 2023 17:24:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675350236195/98a2d380-da50-46e8-a7a0-7be6476b4da9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-redis"><strong>Redis :</strong></h3>
<p>Redis is an open-source, in-memory data structure store, used as a database, cache, and message broker.</p>
<h3 id="heading-memcached">Memcached:</h3>
<p>Memcached is a distributed, high-performance, in-memory caching system. It is used to temporarily store and serve frequently requested data from memory.</p>
<hr />
<h3 id="heading-the-similarity-between-redis-and-memcached">The similarity between Redis and Memcached</h3>
<ul>
<li><p>Both are key-value storage</p>
</li>
<li><p>Both system store data in memory or RAM</p>
</li>
<li><p>Both Redis and Memcached are capable of running on multiple servers</p>
</li>
</ul>
<hr />
<h3 id="heading-data-structure">Data structure</h3>
<ul>
<li><p><strong>Redis:</strong> This supports various ranges of data types based on the additional module and some built-in support. Some data types: strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperlog, and geospatial indexes with radius queries</p>
</li>
<li><p><strong>Memcached:</strong> This support only string as the value in key-value entry</p>
</li>
</ul>
<hr />
<h3 id="heading-transactions">Transactions</h3>
<ul>
<li><p><strong>Memcached</strong> doesn't support transactions, although its operations are atomic.</p>
</li>
<li><p><strong>Redis</strong> provides out-of-the-box support for transactions to execute commands.</p>
</li>
</ul>
<hr />
<h3 id="heading-architecture">Architecture</h3>
<ul>
<li><p><strong>Redis</strong> uses a single-core architecture.</p>
</li>
<li><p><strong>Memcached</strong> implements a multi-threaded architecture by utilizing multiple cores.</p>
</li>
</ul>
<hr />
<h3 id="heading-is-there-any-speciality-in-redis">Is there any speciality in Redis?</h3>
<p>I know this portion is a little bit out of topic. But I have seen, in many blogs or youtube videos, shows redis is the key-value store only to just cache or temporary database.</p>
<p>So let's know a little bit about the full potential of Redis.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675356819084/691ce637-126b-463b-8ee8-495082b9f6c1.png" alt class="image--center mx-auto" /></p>
<p>By enabling different modules, we can achieve the full potential</p>
<ul>
<li><p><strong>RedisJSON</strong> to store JSON database directly in Redis.</p>
</li>
<li><p><strong>RedisGraph</strong> is a graph database built on Redis. This graph database uses GraphBlas under the hood for its sparse adjacency matrix graph representation.</p>
</li>
<li><p><strong>RedisSearch</strong> is a high-performance, full-text search engine that is built as a Redis module, offering efficient indexing and querying capabilities for text-based data within Redis.</p>
</li>
<li><p><strong>RedisTimeSeries</strong> is a Redis module for efficiently storing and querying time-series data, providing functionality for querying and analyzing time-stamped data, such as metrics, events, and logs.</p>
</li>
<li><p><strong>RedisBloom</strong> is a Redis module that provides scalable probabilistic data structures, such as Bloom filters, counting filters, and others, to support high-performance and memory-efficient data analysis and storage operations.</p>
</li>
</ul>
<p>After seeing the modules and capability of Redis, we can only think of this</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675357094759/fac08815-c784-4341-a500-7a3edb3b8ef2.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-now-what-is-best-for-caching">Now, what is best for caching?</h3>
<p>Here we need to think about the data structure.</p>
<p><strong>The best case to use Memcached over Redis</strong></p>
<ul>
<li><p>The cached data format is plain string data to cache like HTML pages, CSS, JS or anything other than that.</p>
</li>
<li><p>The dataset size is going to be very large in future</p>
</li>
</ul>
<p>If these two conditions are satisfied then it will be best to go with <strong>Memcached</strong>.</p>
<p>In other cases, you can go with Redis.</p>
<hr />
<p>We have reached the end of this blog.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675358079530/928c421a-7765-4f1d-a520-7ab3d5da1182.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Docker CLI & Dockerfile In One Shot]]></title><description><![CDATA[In this blog, I will try to provide you with a complete cheat sheet on Docker CLI & YAML so that you can quickly revise the Docker without wasting any time.
This blog is intended for those who have learnt Docker Previously and want to revise that.
If...]]></description><link>https://blog.tanmoysrt.xyz/docker-cli-dockerfile-in-one-shot</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/docker-cli-dockerfile-in-one-shot</guid><category><![CDATA[Docker]]></category><category><![CDATA[Devops]]></category><category><![CDATA[cheatsheet]]></category><category><![CDATA[Dockerfile]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Wed, 04 Jan 2023 16:16:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672849172850/8b3cfcc8-78ff-4385-adeb-53f5b22a61a8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this blog, I will try to provide you with a complete cheat sheet on Docker CLI &amp; YAML so that you can quickly revise the Docker without wasting any time.</p>
<p>This blog is intended for those who have learnt Docker Previously and want to revise that.</p>
<p>If you like this blog, give a 👍 and follow for more content.</p>
<hr />
<h2 id="heading-dockerfile">Dockerfile</h2>
<p>It's just a text file that contains instructions for building a Docker image.</p>
<p>It's just to automate the process that you do manually. So if you know how to do a process manually, you can learn it quickly.</p>
<h3 id="heading-format">Format</h3>
<pre><code class="lang-bash">INSTRUCTION arguments
</code></pre>
<h3 id="heading-instruction-set">Instruction Set</h3>
<p>In the below table, I have mentioned some sort terms. <code>dir</code> -&gt; <code>Directory</code>, <code>src</code> -&gt; <code>Source</code>, <code>dst</code> -&gt; <code>Destination</code></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>INSTRUCTION</td><td>DESCRIPTION</td></tr>
</thead>
<tbody>
<tr>
<td>FROM &lt;image_name&gt;</td><td>Fetch base image for Docker</td></tr>
<tr>
<td>COPY &lt;src_dir_host&gt; &lt;dest_dir_container&gt;</td><td>Copy a folder of the host system to the container</td></tr>
<tr>
<td>WORKDIR &lt;dir_path_contaiiner&gt;</td><td>Set the working directory of the container where the commands will run</td></tr>
<tr>
<td>RUN &lt;command&gt;</td><td>Run commands in a shell</td></tr>
<tr>
<td>RUN [&lt;command arg1&gt;, &lt;command arg2&gt;]</td><td>We can break the command in command args also.  </td></tr>
</tbody>
</table>
</div><p>Ex : <code>RUN "apt-get update"</code> -&gt; <code>RUN ["apt-get", "update"]</code> |
| ENV &lt;key&gt;=&lt;value&gt; | Set environment variables |
| EXPOSE &lt;container_port&gt; | Expose the port of a container to make it accessible in the same network |
| ENTRYPOINT &lt;command&gt; | That command will execute as soon as the container boot up |
| ENTRYPOINT [&lt;command arg1&gt;, &lt;command arg2&gt;] | We can break the command in command args also.<br />Ex : <code>RUN "/bin/sh sample.sh"</code> -&gt; <code>RUN ["/bin/sh", "sample.sh"]</code> |</p>
<p>There is one more command, which you see mostly. <code>CMD</code></p>
<p>The purpose of this command is to run the commands specified in arguments. It also has two formats, for example.</p>
<ul>
<li><p>CMD echo "hello-world."</p>
</li>
<li><p>CMD ["/bin/sh", "echo", "hello-world"]</p>
</li>
</ul>
<p>You might be confused now about the difference between <strong>RUN</strong> and <strong>CMD.</strong></p>
<ul>
<li><p><code>RUN</code> runs all the commands specified in the argument</p>
</li>
<li><p>For <code>CMD</code> there is some particular case.</p>
<ul>
<li><p>If you have provided some commands to run in <code>docker run</code> command, <code>CMD</code> is going to be ignored.</p>
</li>
<li><p>If you have listed multiple CMD statements, only the last CMD will be executed.</p>
</li>
<li><p>IF <code>ENTRYPOINT</code> in Dockerfile is provided, <code>CMD</code> it is going to be ignored.</p>
</li>
<li><p>In any container deployment platform, you can see the <code>CMD</code> to run manually.</p>
</li>
</ul>
</li>
</ul>
<p>🔵 As the blog's purpose is to give concise details of Dockerfile and CLI, we are not attaching Dockerfile examples here. But will create some blogs on Dockerfile and attach links to them.</p>
<hr />
<h2 id="heading-docker-cli">Docker CLI</h2>
<h3 id="heading-arguments-list">Arguments List</h3>
<table><tbody><tr><td><p><strong>Argument</strong></p></td><td><p><strong>Description</strong></p></td></tr><tr><td><p>-u</p></td><td><p>Username</p></td></tr><tr><td><p>--name</p></td><td><p>Name [Normally used for container]</p></td></tr><tr><td><p>-d</p></td><td><p>Detach [Run in the background]</p></td></tr><tr><td><p>-a</p></td><td><p>All [Stopped + Paused + Running]</p></td></tr><tr><td><p>-i</p></td><td><p>Interactive</p></td></tr><tr><td><p>-t</p></td><td><p>- tty [stdin] [For Container]<br />- tag name [For Image]</p></td></tr><tr><td><p>-it</p></td><td><p>Interactive with stdin</p></td></tr><tr><td><p>-w</p></td><td><p>Working directory [<em>example</em> -w '/opt/test']</p></td></tr><tr><td><p>-p</p></td><td><p>Port [Example : -p &lt;host_system_port&gt;:&lt;container_port&gt; ]</p></td></tr><tr><td><p>-v</p></td><td><p>Volume Mount [Example : -p &lt;host_system_volume_path&gt;:&lt;container_volume_path&gt; ]</p></td></tr><tr><td><p>-e</p></td><td><p>Environment Variable [Example : -e &lt;variable_name&gt;=&lt;value&gt; ]</p></td></tr></tbody></table>

<h3 id="heading-image-specific-commands">Image Specific Commands</h3>
<p><strong>List all local images</strong></p>
<pre><code class="lang-bash">docker images
</code></pre>
<p><strong>Build Image From</strong> <code>Dockerfile</code> <strong>in current directory</strong></p>
<pre><code class="lang-bash">docker build . -t &lt;tag_name&gt;
</code></pre>
<p><strong>Pull an image from Dockerhub</strong></p>
<pre><code class="lang-bash">docker pull &lt;image_name&gt;
<span class="hljs-comment"># example : docker pull redis</span>
</code></pre>
<p><strong>Delete an image</strong></p>
<pre><code class="lang-bash">docker rmi redis
</code></pre>
<p><strong>Remove all unused images</strong></p>
<pre><code class="lang-bash">docker image prune
</code></pre>
<h3 id="heading-container-specific-commands"><strong>Container Specific Commands</strong></h3>
<p><strong>Run a docker container from an image</strong></p>
<pre><code class="lang-bash">docker run &lt;image_name&gt;
</code></pre>
<blockquote>
<p>Now you can refer the <strong>Arguments List</strong> table to choose your required arguments</p>
<p>I am solving an question for example.</p>
<p>Let's assume, I need to create an container from image of <strong>redis</strong> with port mapping from container port 6379 to host port 6379 . The name will be <strong>redis-instance-1 .</strong> Make the instance detachable &amp; run <code>redis-server --requirepass "SECRET_PASSWORD"</code> at its beginning.</p>
<pre><code class="lang-bash">docker run --name redis-instance-1 -d -p 6379:6379 redis redis-server --requirepass <span class="hljs-string">"SECRET_PASSWORD"</span>
</code></pre>
<blockquote>
<p><strong>Its important to notice that , you need to pass all the arguments before providing the image name and entrypoint_command</strong></p>
</blockquote>
</blockquote>
<p><strong>List containers [only Running]</strong></p>
<pre><code class="lang-bash">docker ps
</code></pre>
<p><strong>List all containers [Stopped + Paused + Running]</strong></p>
<pre><code class="lang-bash">docker ps -a
</code></pre>
<p><strong>Start or Stop a container</strong></p>
<pre><code class="lang-bash">docker start|stop &lt;container_name or container_id&gt;
</code></pre>
<blockquote>
<p>You can get the <code>Container ID</code> by running the command for list all container</p>
</blockquote>
<p><strong>Remove a stopped container</strong></p>
<pre><code class="lang-bash">docker rm &lt;container_name or container_id&gt;
</code></pre>
<p><strong>Attach to the current process of container</strong></p>
<pre><code class="lang-bash">docker attach &lt;container_name or container_id&gt;
</code></pre>
<p><strong>Run a command in the container</strong></p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> &lt;container_name or container_id&gt; &lt;<span class="hljs-built_in">command</span>&gt;
</code></pre>
<blockquote>
<p>Example : Start a bash terminal in redis instance</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -it redis /bin/sh
</code></pre>
</blockquote>
<p><strong><em>❓You may have a question. What's the difference between exec and attach, then</em></strong></p>
<p>With attach, we attach to the process that's currently running in the container</p>
<p>But with exec, we can run a new process in a container without hampering the running process of the container</p>
<p><strong>Log the data of the current process of the container</strong></p>
<pre><code class="lang-bash">docker logs -f &lt;container_name or container_id&gt;
</code></pre>
<p><strong>Inspect and grab all the details of a container</strong></p>
<pre><code class="lang-bash">docker inspect &lt;container_name or container_id&gt;
</code></pre>
<blockquote>
<p>It will return the details in an JSON format</p>
</blockquote>
<p>Check the stats [CPU, RAM, Network, Storage usage] for all running containers</p>
<pre><code class="lang-bash">docker container stats
</code></pre>
<hr />
<p>🏄 You have liked this blog and gained some knowledge, please consider to like &amp; share with your friends.</p>
]]></content:encoded></item><item><title><![CDATA[Deploy  AI Models with RabbitMQ Message Broker]]></title><description><![CDATA[⚠ Disclaimer
This blog is focused on the situation when you need to handle a low number of users to access your AI models, like in a hackathon or a prototype of a product which may not be accessed by more than 500s people concurrently. More optimizat...]]></description><link>https://blog.tanmoysrt.xyz/deploy-ai-models-with-rabbitmq-message-broker</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/deploy-ai-models-with-rabbitmq-message-broker</guid><category><![CDATA[AI]]></category><category><![CDATA[Python]]></category><category><![CDATA[rabbitmq]]></category><category><![CDATA[queue]]></category><category><![CDATA[Microservices]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Tue, 27 Dec 2022 09:17:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671775779794/f4799720-8bb6-46b0-82ba-34a6ff39f07a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-disclaimer">⚠ <strong>Disclaimer</strong></h1>
<p>This blog is focused on the situation when you need to handle a low number of users to access your AI models, like in a hackathon or a prototype of a product which may not be accessed by more than 500s people concurrently. More optimization and robust design are required for production usage. But this blog can be a good starting point.</p>
<hr />
<h1 id="heading-lets-discuss-the-problem-with-client-server-architecture">🏊 <strong>Let's discuss the problem with Client-Server architecture.</strong></h1>
<p>We all know maximum AI models are resource-hungry operations and take at least from 1 second to up to 5 minutes, especially for large deep learning models.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672063146321/7ccb1a38-67b4-4cf3-b134-18fbee62810f.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>The main problem is that we can't run too many requests in a low-end system (2GB RAM, 2vCPUs).</p>
</li>
<li><p>As we have 2 CPU cores, running more than two threads is impossible. As a result, the <em>system crashed</em>.</p>
</li>
<li><p>If the processing time of the model exceeds Nginx/web gateway timeout, it will give the user an error and waste the system's resources.</p>
<hr />
</li>
</ul>
<h1 id="heading-now-whats-our-approach"><strong>🏂 Now, What's our approach?</strong></h1>
<p><strong>We will take the microservice approach and split our system into three parts. So that user can get a message asap about the request received by the server and later can enquire about the result.</strong></p>
<ul>
<li><p>Flask Web Server</p>
</li>
<li><p>RabbitMQ as message broker and queue management [It comes as packaged software. We will use a cloud-based free one. I will discuss this in a later part]</p>
</li>
<li><p>Worker process - will be responsible for running the input data on AI models.</p>
</li>
</ul>
<p><strong>Let's understand the overall architecture of the system by ⏬</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672074982423/a29356fc-39bc-43e0-90bd-91e2852388d2.png" alt class="image--center mx-auto" /></p>
<p>Before going into more depth, let's know the process in short</p>
<ol>
<li><p>The user will send the request to the server</p>
</li>
<li><p>The server will create an entry in a table with status <strong>processing</strong></p>
</li>
<li><p>The server then sends the input and request ID to the RabbitMQ message broker</p>
</li>
<li><p>The worker process will receive the request ID and input. It will run the AI model and generate the output based on the received input.</p>
</li>
<li><p>Then the worker process will submit the result to the server and mark the request-id status as <strong>done.</strong></p>
</li>
<li><p>During this, the end-user can request the server for its result. If the result is available to the server, the end-user will get the result else; the end-user will resend the request in a while.</p>
<hr />
</li>
</ol>
<h1 id="heading-detailed-concept"><strong>👀 Detailed Concept</strong></h1>
<p>We will first clarify how this will work and solve our issue of limited resources. Then we will move to code.</p>
<h3 id="heading-1-process-new-request-coming-from-end-user"><strong>1️⃣ Process New Request Coming From End-user</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672077154372/9b457a2c-8f6e-4d09-87ba-e8d7a09c4492.png" alt class="image--center mx-auto" /></p>
<p>As soon as the request is received, the backend will do three tasks one by one</p>
<ol>
<li><p>Make an entry in the <strong>Request Status Track Table</strong> to keep track of request</p>
</li>
<li><p>Push the request details <strong>&lt;Request ID, Input&gt;</strong> to the queue</p>
</li>
<li><p>Send an acknowledgement message to the user that the request is processing. Also, send the <strong>Request ID</strong> with the response so that the user can enquire about the result later</p>
</li>
</ol>
<h3 id="heading-2-consumerworker-pop-process-from-queue-and-process-it"><strong>2️⃣ Consumer/Worker: Pop Process From Queue and Process It</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672077207894/a81717f7-ca13-49a9-a5e2-a595e7571626.png" alt class="image--center mx-auto" /></p>
<p>The consumer/worker listens for new requests, and RabbitMQ is responsible for giving the task to its listeners. It will follow the following steps.</p>
<ol>
<li><p>The worker will extract the <strong>Request ID</strong> and <strong>Input</strong> it from the received payload.</p>
</li>
<li><p>The worker will run the input to the <strong>AI Modal</strong> and prepare the <strong>output</strong>.</p>
</li>
<li><p>Then the worker will update the <strong>output</strong> and <strong>status to done</strong> by specifying the request ID. Now, this can be done in two ways -</p>
<ul>
<li><p>Connect to the database directly</p>
</li>
<li><p>Call API of the backend [<strong><em>Recommended</em></strong>]</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-3-fetch-result-of-request-by-the-end-user"><strong>3️⃣ Fetch Result of Request by the End-user</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672077218656/a05cea77-9c82-4079-8e96-6ba140acb334.png" alt class="image--center mx-auto" /></p>
<p>After a fixed interval(for example, 5 sec), the end-user will request the backend to send the result of his query.</p>
<p>Now the process flow of the backend will be</p>
<ol>
<li><p>It will check the status of the request by its ID.</p>
</li>
<li><p>If the status is still <strong>processing</strong>, the backend will tell the end-user about its status and will say to them to re-request later.</p>
</li>
<li><p>If the status is <strong>done</strong>, the backend will send the output to the end user.</p>
</li>
</ol>
<p><strong>That's all !</strong></p>
<hr />
<h1 id="heading-its-coding-time"><strong>💻 It's Coding Time</strong></h1>
<h2 id="heading-read-this-note-before-approaching-coding-part"><strong>⚠ Read This Note Before Approaching Coding Part</strong></h2>
<p>Using an actual AI model's code will complicate this writing. We prefer to simulate that by a long-run function.</p>
<p>As an example, we will calculate the factorial of a large number.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_factorial</span>(<span class="hljs-params">n</span>):</span>
    result = <span class="hljs-number">1</span>
    <span class="hljs-keyword">if</span> n &gt; <span class="hljs-number">1</span>:
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, n+<span class="hljs-number">1</span>):
            result = result * i
    <span class="hljs-keyword">return</span> result
</code></pre>
<p>For factorial(n), n &gt; 150000, it takes more than 10 seconds to compute</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672122450777/362ee721-e1a6-4203-897d-4252c1513836.png" alt class="image--center mx-auto" /></p>
<p>It's perfect for our use case.</p>
<h2 id="heading-current-backend-in-flask">🕰 Current Backend In Flask</h2>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, request

<span class="hljs-comment"># Function to calculate the factorial of a number</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_factorial</span>(<span class="hljs-params">n</span>):</span>
    result = <span class="hljs-number">1</span>
    <span class="hljs-keyword">if</span> n &gt; <span class="hljs-number">1</span>:
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, n+<span class="hljs-number">1</span>):
            result = result * i
    <span class="hljs-keyword">return</span> result

<span class="hljs-comment"># create the Flask app</span>
app = Flask(__name__) 

<span class="hljs-comment"># route to calculate the factorial of a number</span>
<span class="hljs-meta">@app.route('/factorial', methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factorial_handler</span>():</span>
    no = int(request.args.get(<span class="hljs-string">'no'</span>))
    result = calculate_factorial(no)
    <span class="hljs-keyword">return</span> str(result)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">False</span>)
</code></pre>
<p>Try to run the 5~6 requests at a time and see what happened</p>
<pre><code class="lang-bash">curl http://127.0.0.1:5000/factorial?no=150000
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672124191134/58d658f5-7340-4298-98cb-ac2978aa18a9.png" alt class="image--center mx-auto" /></p>
<p>See, the last request takes more than 1 minute 💣💣.</p>
<p>As the processing time of the function increases, the waiting time per user will increase exponentially.</p>
<h2 id="heading-time-to-rebuild-our-backend"><strong>⏰ Time To Rebuild Our Backend</strong></h2>
<h3 id="heading-first-create-a-cloud-hosted-rabbitmq-service">🟠 <strong>First, create a cloud-hosted RabbitMQ service</strong></h3>
<ul>
<li><p>Go to <a target="_blank" href="https://www.cloudamqp.com/">https://www.cloudamqp.com/</a> and create a free account</p>
</li>
<li><p>Create a free RabbitMQ instance</p>
</li>
<li><p>Click on the <strong>name</strong> of the instance</p>
</li>
<li><p>Copy the <strong>URL</strong> from <strong>AMQP</strong> <strong>details</strong>.</p>
</li>
</ul>
<h3 id="heading-run-an-redis-instance-locally"><strong>🟡 Run An Redis Instance Locally</strong></h3>
<ul>
<li><p>You can follow the guide to install Redis in your system. <a target="_blank" href="https://redis.io/docs/getting-started/installation/">https://redis.io/docs/getting-started/installation/</a></p>
</li>
<li><p>Run the Redis server locally by running this command</p>
<pre><code class="lang-bash">  redis-server
</code></pre>
</li>
</ul>
<h3 id="heading-prepare-the-helper-functions-beforehand"><strong>🟢 Prepare the helper functions beforehand</strong></h3>
<p>We need to create some functions -</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Function</td><td>Definition</td></tr>
</thead>
<tbody>
<tr>
<td>publish_to_rabbitMQ(data)</td><td>It will publish the data to rabbitMQ</td></tr>
<tr>
<td>create_request(input)</td><td>Create a request entry in Redis, do an entry in RabbitMQ and return the <strong>ID of the request</strong></td></tr>
<tr>
<td>get_request(request_id)</td><td>It will fetch the request details by the id from Redis</td></tr>
<tr>
<td>update_request(request_id, status, output)</td><td>It will update the status and output of the request in Redis</td></tr>
</tbody>
</table>
</div><p><strong>Implementation of publish_to_rabbitMQ(data):</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> pika

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">publish_to_rabbitMQ</span>(<span class="hljs-params">data</span>):</span>
    <span class="hljs-comment"># Create connection</span>
    connection = pika.BlockingConnection(pika.URLParameters(<span class="hljs-string">"amqps://yyyyyy:xxxxxxxxx@puffin.rmq2.cloudamqp.com/yyyyyy"</span>))
    channel = connection.channel()
    <span class="hljs-comment"># Create queue . For now queue name is factorial_process</span>
    channel.queue_declare(queue=<span class="hljs-string">'factorial_process'</span>, durable=<span class="hljs-literal">True</span>)
    <span class="hljs-comment"># Publish the message to the queue</span>
    channel.basic_publish(exchange=<span class="hljs-string">''</span>, routing_key=<span class="hljs-string">'factorial_process'</span>, body=json.dumps(data))
    <span class="hljs-comment"># Close the connection</span>
    connection.close()
</code></pre>
<p><strong>Implementation of create_request(input) :</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_request</span>(<span class="hljs-params">input</span>):</span>
    <span class="hljs-comment"># Generate a random ID</span>
    random_id = str(uuid.uuid4())
    <span class="hljs-comment"># Store the request in Redis</span>
    redis_instnace.set(random_id, json.dumps({<span class="hljs-string">'input'</span>: input, <span class="hljs-string">'status'</span>: <span class="hljs-string">'processing'</span>, <span class="hljs-string">'output'</span>: <span class="hljs-string">''</span>}))
    <span class="hljs-comment"># Publish the request to RabbitMQ</span>
    publish_to_rabbitMQ({<span class="hljs-string">'request_id'</span>: random_id, <span class="hljs-string">'input'</span>: input})
    <span class="hljs-comment"># Return the request ID</span>
    <span class="hljs-keyword">return</span> random_id
</code></pre>
<p><strong>Implementation of get_request(request_id) :</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_request</span>(<span class="hljs-params">request_id</span>):</span>
    request_data = redis_instnace.get(request_id)
    <span class="hljs-keyword">if</span> request_data:
        <span class="hljs-keyword">return</span> json.loads(request_data)
    <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>
</code></pre>
<p><strong>Implementation of update_request(request_id, status, output):</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update_request</span>(<span class="hljs-params">request_id, status, output</span>):</span>
    request_details = get_request(request_id)
    redis_instnace.set(request_id, json.dumps({<span class="hljs-string">'input'</span>: request_details[<span class="hljs-string">'input'</span>], <span class="hljs-string">'status'</span>: status, <span class="hljs-string">'output'</span>: output}))
</code></pre>
<h3 id="heading-re-design-flask-backend"><strong>🔵 Re-design Flask Backend</strong></h3>
<ul>
<li><p>We will remove the processing part from it</p>
</li>
<li><p>Create two more APIs</p>
<ul>
<li><p><strong>/factorial/result?id=random:</strong> To fetch the results of the request</p>
</li>
<li><p><strong>/factorial/update:</strong> To update the result and status of the request</p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, request
<span class="hljs-keyword">from</span> helpers <span class="hljs-keyword">import</span> create_request, get_request, update_request

<span class="hljs-comment"># create the Flask app</span>
app = Flask(__name__) 

<span class="hljs-comment"># route to queue the request</span>
<span class="hljs-meta">@app.route('/factorial', methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factorial_handler</span>():</span>
    no = int(request.args.get(<span class="hljs-string">'no'</span>))
    id = create_request(no)
    <span class="hljs-keyword">return</span> id

<span class="hljs-comment"># route to get the result</span>
<span class="hljs-meta">@app.route('/factorial/result', methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factorial_result_handler</span>():</span>
    id = request.args.get(<span class="hljs-string">'id'</span>)
    result = get_request(id)
    <span class="hljs-keyword">return</span> result

<span class="hljs-comment"># route to update the result</span>
<span class="hljs-meta">@app.route('/factorial/update', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factorial_update_handler</span>():</span>
    body = request.get_json()
    id = body[<span class="hljs-string">'id'</span>]
    status = body[<span class="hljs-string">'status'</span>]
    output = body[<span class="hljs-string">'output'</span>]
    update_request(id, status, output)
    <span class="hljs-keyword">return</span> <span class="hljs-string">'OK'</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">False</span>)
</code></pre>
<h3 id="heading-build-the-consumer"><strong>⚪️ Build The Consumer</strong></h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pika
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> requests

<span class="hljs-comment"># Function to calculate the factorial of a number</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_factorial</span>(<span class="hljs-params">n</span>):</span>
    result = <span class="hljs-number">1</span>
    <span class="hljs-keyword">if</span> n &gt; <span class="hljs-number">1</span>:
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, n+<span class="hljs-number">1</span>):
            result = result * i
    <span class="hljs-keyword">return</span> result

<span class="hljs-comment"># Create a callback function</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">callback</span>(<span class="hljs-params">ch, method, properties, body</span>):</span>
    body = json.loads(body)
    request_id = body[<span class="hljs-string">'request_id'</span>]
    print(<span class="hljs-string">'Received request with ID: '</span>, request_id)
    input = body[<span class="hljs-string">'input'</span>]
    output = calculate_factorial(input)
    <span class="hljs-comment"># Update the status to done</span>
    requests.post(<span class="hljs-string">'http://localhost:5000/factorial/update'</span>, json={<span class="hljs-string">'id'</span>: request_id, <span class="hljs-string">'status'</span>: <span class="hljs-string">'done'</span>, <span class="hljs-string">'output'</span>: output})

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start_consumer</span>():</span>
    <span class="hljs-comment"># Create connection</span>
    connection = pika.BlockingConnection(pika.URLParameters(<span class="hljs-string">"amqps://yyyyyy:xxxxxxxxx@puffin.rmq2.cloudamqp.com/yyyyyy"</span>))
    channel = connection.channel()
    <span class="hljs-comment"># Create queue . For now queue name is factorial_process</span>
    channel.queue_declare(queue=<span class="hljs-string">'factorial_process'</span>, durable=<span class="hljs-literal">True</span>)
    <span class="hljs-comment"># Listen to the queue and </span>
    <span class="hljs-comment"># call the callback function on receiving a message</span>
    channel.basic_consume(queue=<span class="hljs-string">'factorial_process'</span>, on_message_callback=callback, auto_ack=<span class="hljs-literal">True</span>)
    <span class="hljs-comment"># Start consuming</span>
    channel.start_consuming()

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    start_consumer()
</code></pre>
<h2 id="heading-lets-see-that-in-action"><strong>📢 Let's see that in action</strong></h2>
<p><strong>Let's send a request to the backend server.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672131210820/48c57d77-099c-4e01-89a0-fb356f8a469d.png" alt class="image--center mx-auto" /></p>
<p>That's our request id <strong><em>748879f5-6504-4fbf-823a-74e6c44a3357</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672131241612/daf4e1b5-0123-49bd-9b79-a6ca190bb1dc.png" alt class="image--center mx-auto" /></p>
<p>The consumer is running 🔥. We can also see the consumer has received the request bearing id <strong><em>748879f5-6504-4fbf-823a-74e6c44a3357</em></strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672131264640/68642a9f-bacf-41d7-a14e-933056dc2df7.png" alt class="image--center mx-auto" /></p>
<p>We queried the server with the id. But that is still processing.</p>
<p>-&gt; After some time 🕓, we rerun the query. And this time, we got our results. <em>The result is too long to show here. So truncated the output.</em></p>
<pre><code class="lang-bash">curl http://127.0.0.1:5000/factorial/result?id=748879f5-6504-4fbf-823a-74e6c44a3357

&gt; {<span class="hljs-string">"input"</span>: 150000, <span class="hljs-string">"output"</span>:<span class="hljs-string">"....truncated"</span>, <span class="hljs-string">"status"</span>: <span class="hljs-string">"done"</span>}
</code></pre>
<p><strong>🚀🚀 Congratulations. That's all.</strong></p>
<blockquote>
<ul>
<li><p>You can spin many consumers to make the resulting process much faster.</p>
</li>
<li><p>Not only AI model, but you can also build many things based on this concept of microservice architecture.</p>
</li>
<li><p>Whatever, with this design, when your userbase grows results may come a bit late but your backend will not be unresponsive. To make it faster you can spin more consumers.</p>
</li>
</ul>
</blockquote>
<hr />
<h2 id="heading-some-optimization-tips"><strong>⚡Some Optimization Tips</strong></h2>
<ul>
<li><p>The polling method is acceptable but is not suitable for large users. We can use WebSocket in place of polling to reduce network calls.</p>
</li>
<li><p>We should consider deleting the <strong>processed</strong> request records from the database as they have no use.</p>
</li>
<li><p>We can also consider using an in-memory database like <strong>Redis</strong> to store the data of <strong>requests</strong>.</p>
</li>
<li><p>The endpoints must be secured so the internal consumer/worker can access them.</p>
</li>
<li><p>Make the consumer/worker dockerize so it can be easy to run multiple consumers using Amazon EKS, ECS, or other services.</p>
<hr />
<p>  <em>If you liked this blog, share this blog and subscribe to the newsletter.</em></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Reactivity in Javascript]]></title><description><![CDATA[👀 What is Reactivity?
It's the ability of a piece of code to automatically update or re-render in response to changes in the data it is bound to.
Let's try to understand clearly by ⏬

Selling Price and Buying Price are two state variables on which t...]]></description><link>https://blog.tanmoysrt.xyz/reactivity-in-javascript</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/reactivity-in-javascript</guid><category><![CDATA[React]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[design patterns]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Fri, 23 Dec 2022 06:14:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671722952230/0e40d03f-bae3-4b09-a3a8-8ca52b6890a7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-reactivity"><strong>👀 What is Reactivity?</strong></h2>
<p>It's the ability of a piece of code to automatically update or re-render in response to changes in the data it is bound to.</p>
<p>Let's try to understand clearly by ⏬</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671735675701/6ee6f7e7-b564-488a-8e96-07c3b474d52a.png" alt class="image--center mx-auto" /></p>
<p><strong>Selling Price</strong> and <strong>Buying Price</strong> are two state variables on which the value of <strong>Profit</strong> depends.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671735710574/f4010b92-78b6-4bce-aca4-4880ec45e4db.png" alt class="image--center mx-auto" /></p>
<p><strong>In the case of a Reactive System,</strong></p>
<p>The profit variable will be updated upon any changes in <strong>Selling Price</strong> or <strong>Buying Price</strong>.</p>
<p>In the initial state, Selling price is 500 and Buying Price is 300, So the Profit will be (500-300) = 200.</p>
<p>When we update buying Price to 100, the Profit is recalculated automatically and updated to (500-100)=400</p>
<p><strong>In the case of a non-reactive system,</strong></p>
<p>Upon any changes in <strong>Selling Price</strong> or <strong>Buying Price</strong>, the profit variable will not be updated until <strong><em>calculateProfit() gets called again.</em></strong></p>
<p>So, In the initial state, Selling price is 500 and Buying Price is 300, So the Profit will be (500-300) = 200.</p>
<p>When we update buying Price to 100, the Profit remains the same as before. (500-300) = 200</p>
<hr />
<h2 id="heading-where-is-the-reactivity-concept-used"><strong>🤔 Where is the Reactivity concept used?</strong></h2>
<p>The reactivity concept is in the ❤️ of all modern frontend frameworks (React, Next.js, Vue.js, etc.).</p>
<p>Some important parts where this concept and programming practice are used -</p>
<ul>
<li><p>useState hook of React.js</p>
</li>
<li><p>re-render widgets when some bounded state variable got updated</p>
</li>
</ul>
<hr />
<h2 id="heading-let-us-start-building-a-reactive-system"><strong>🚀🚀 Let us start building a reactive system</strong></h2>
<h3 id="heading-start-with-a-simple-non-reactive-system"><strong>Start with a simple non-reactive system</strong></h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> buyingPrice = <span class="hljs-number">200</span>
<span class="hljs-keyword">let</span> sellingPrice = <span class="hljs-number">500</span>

<span class="hljs-keyword">let</span> profit;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateProfit</span>(<span class="hljs-params"></span>)</span>{
    profit = sellingPrice - buyingPrice
}

calculateProfit()
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Profit : "</span>+profit) <span class="hljs-comment">// Profit : 300</span>

<span class="hljs-comment">// Update the selling price</span>
buyingPrice = <span class="hljs-number">100</span>

<span class="hljs-comment">// call calculateProfit() to recalculate</span>
calculateProfit()
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Profit : "</span>+profit) <span class="hljs-comment">// Profit : 400</span>
</code></pre>
<h3 id="heading-let-us-begin-creating-a-reactive-system"><strong>Let us begin creating a reactive system</strong></h3>
<h3 id="heading-step-1-create-a-dependency-class"><strong>Step 1: Create a Dependency Class</strong></h3>
<p>Manage the dependencies, who need to be notified when this data got updated or modified.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DependancyTracker</span></span>{
    <span class="hljs-keyword">constructor</span>(){
        <span class="hljs-built_in">this</span>.subscribers = []
    }
    <span class="hljs-comment">// Register the function of dependent code</span>
    depend(){
        <span class="hljs-keyword">if</span>(target &amp;&amp; <span class="hljs-built_in">this</span>.subscribers.includes(target) !== <span class="hljs-literal">true</span>){
            <span class="hljs-built_in">this</span>.subscribers.push(target);
        }
    }
    <span class="hljs-comment">// Notify the dependent codes to act on update of this data</span>
    notify(){
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-built_in">this</span>.subscribers.length; i++) {
            <span class="hljs-keyword">let</span> func = <span class="hljs-built_in">this</span>.subscribers[i];
            func(); <span class="hljs-comment">// run the function</span>
        }
    }
}
</code></pre>
<p>Let's see that in action</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> track = <span class="hljs-keyword">new</span> DependancyTracker();
<span class="hljs-keyword">let</span> profit;
<span class="hljs-keyword">let</span> buyingPrice = <span class="hljs-number">200</span>;
<span class="hljs-keyword">let</span> sellingPrice = <span class="hljs-number">400</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateProfit</span>(<span class="hljs-params"></span>)</span>{
    profit = sellingPrice - buyingPrice
}

<span class="hljs-comment">// Register the depndent code</span>
target = calculateProfit
track.depend()
target()

<span class="hljs-comment">// Initial profit </span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Profit : "</span>+profit) <span class="hljs-comment">// Profit : 200</span>

<span class="hljs-comment">// Update the selling price</span>
sellingPrice = <span class="hljs-number">500</span>

<span class="hljs-comment">// Notify all the dependent codes for re-compute</span>
track.notify(); 
<span class="hljs-comment">// calculateProfit is also an part of the dependent codes.</span>

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Profit : "</span>+profit) <span class="hljs-comment">// Profit : 300</span>
</code></pre>
<h3 id="heading-step-2-play-with-the-getter-and-setter"><strong>Step 2: Play with the getter and setter</strong></h3>
<p>A dictionary to store initial values</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> data = {
    <span class="hljs-string">"buyingPrice"</span> : <span class="hljs-number">200</span>
}
</code></pre>
<p>Let's set getter and setter for the specified key</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> internalvalue = data.buyingPrice;

<span class="hljs-built_in">Object</span>.defineProperty(data, <span class="hljs-string">"buyingPrice"</span>, {
    <span class="hljs-attr">get</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Get trigerred"</span>);
        <span class="hljs-keyword">return</span> internalvalue;
    },
    <span class="hljs-attr">set</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">val</span>) </span>{
        internalvalue = val;
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Set trigerred"</span>)
    }
})
</code></pre>
<p>Let's see that in action</p>
<pre><code class="lang-javascript">data.buyingPrice=<span class="hljs-number">900</span>
<span class="hljs-built_in">console</span>.log(data.buyingPrice)
</code></pre>
<p>Output -</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671740146135/c4baa7ea-cd6a-4a6c-a2cf-4f2518415868.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-3-create-a-watch-function-to-make-the-process-a-little-bit-easy"><strong>Step 3: Create a watch function to make the process a little bit easy</strong></h3>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">watch</span>(<span class="hljs-params">func</span>)</span>{
    target = func;
    target();
    target = <span class="hljs-literal">null</span>;
}
</code></pre>
<h3 id="heading-step-4-wrap-up"><strong>Step 4: Wrap up !!!</strong></h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> data = {
    <span class="hljs-string">"buyingPrice"</span> : <span class="hljs-number">200</span>,
    <span class="hljs-string">"sellingPrice"</span>: <span class="hljs-number">400</span>
}

<span class="hljs-keyword">let</span> target = <span class="hljs-literal">null</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DependancyTracker</span></span>{
    <span class="hljs-keyword">constructor</span>(){
        <span class="hljs-built_in">this</span>.subscribers = []
    }
    depend(){
        <span class="hljs-keyword">if</span>(target &amp;&amp; <span class="hljs-built_in">this</span>.subscribers.includes(target) !== <span class="hljs-literal">true</span>){
            <span class="hljs-built_in">this</span>.subscribers.push(target);
        }
    }
    notify(){
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-built_in">this</span>.subscribers.length; i++) {
            <span class="hljs-built_in">this</span>.subscribers[i]();
        }
    }
}

<span class="hljs-built_in">Object</span>.keys(data).forEach(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> {
    <span class="hljs-keyword">let</span> internal = data[key];
    <span class="hljs-keyword">let</span> dep = <span class="hljs-keyword">new</span> DependancyTracker()

    <span class="hljs-built_in">Object</span>.defineProperty(data, key, {
        <span class="hljs-attr">get</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
            dep.depend(); <span class="hljs-comment">// link target function</span>
            <span class="hljs-keyword">return</span> internal;
        },
        <span class="hljs-attr">set</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">val</span>) </span>{
            internal = val; <span class="hljs-comment">// set value</span>
            dep.notify(); <span class="hljs-comment">// notify dependent variables linked funtion</span>
        }
    })

})

<span class="hljs-comment">// Watch function</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">watch</span>(<span class="hljs-params">func</span>)</span>{
    target = func;
    target();
    target = <span class="hljs-literal">null</span>;
}

<span class="hljs-comment">// Link calculateProfit function in watch</span>
watch(<span class="hljs-function">() =&gt;</span> {
    data.profit = data.sellingPrice - data.buyingPrice
})

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Profit : "</span>+data.profit) <span class="hljs-comment">// Profit : 200</span>

data.sellingPrice = <span class="hljs-number">700</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Profit : "</span>+data.profit) <span class="hljs-comment">// Profit : 500</span>

data.sellingPrice = <span class="hljs-number">900</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Profit : "</span>+data.profit) <span class="hljs-comment">// Profit : 700</span>
</code></pre>
<h3 id="heading-congratulations"><strong>Congratulations 🎉🎉</strong></h3>
<p>You may have gained an amazing concept from this blog. If you like it, please share it with your friends.</p>
]]></content:encoded></item><item><title><![CDATA[What are Singleton classes and Why do we need them?]]></title><description><![CDATA[What is Singleton Class?
While doing projects, we sometimes want to keep only one instance of a class and don't want to pass the instance of an object by argument in each function.

class ClassA {
      // sample codes
}

object1 = ClassA();
object2 ...]]></description><link>https://blog.tanmoysrt.xyz/what-are-singleton-classes-and-why-do-we-need-them</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/what-are-singleton-classes-and-why-do-we-need-them</guid><category><![CDATA[Singleton Design Pattern]]></category><category><![CDATA[singleton]]></category><category><![CDATA[BlogsWithCC]]></category><category><![CDATA[#BlogsWithCC on Hashnode]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sun, 27 Nov 2022 19:09:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669569411821/Jh_1SygRy.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-singleton-class">What is Singleton Class?</h2>
<p>While doing projects, we sometimes want to <strong>keep only one instance of a class and don't want to pass the instance of an object by argument in each function</strong>.</p>
<pre><code class="lang-java">
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ClassA</span> </span>{
      <span class="hljs-comment">// sample codes</span>
}

object1 = ClassA();
object2 = ClassA();
object3 = ClassA();
</code></pre>
<p>In the above example, we want that when we <strong>call the ClassA constructor, every time it returns the same instance of an object in memory</strong> instead of creating a new thing every time the constructor is called.</p>
<h2 id="heading-when-do-we-need-singleton-class">When do we need Singleton Class?</h2>
<p>Let's discuss the real-life use of singleton class.</p>
<ul>
<li><p><strong>API Client :</strong> During website / android / ios / native application development, we usually need to design an API client to establish communication between our app and server. 90% of the time, the API request is protected by some sort of authentication mechanism.</p>
<p>If we create an instance of an API client for sending each API request, we need to configure the client with authentication details (JWT Key, API Key, Bearer Token, etc.).</p>
<p>But we don't want to do this thing again and again for each request. Here we can use the concept of Singleton Class and resolve the issue.</p>
</li>
<li><p><strong>Database Client :</strong> Like the issues for API Client, in the case of database client we have a limit on creating instances of objects of particular database clients. So we need to use only a single instance of Database Client / ORM Client in the whole project.</p>
</li>
</ul>
<h2 id="heading-what-is-the-concept-behind-singleton-class">What is the concept behind Singleton Class?</h2>
<p>In every programming language, we get a special type of variable <strong>static</strong> for class, which helps to keep only a single instance of the variable in all object instances of that particular class.</p>
<p><em>Let's get started learning this</em></p>
<ul>
<li><p>Let's define a dummy class</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExampleA</span></span>{
  <span class="hljs-comment">// Class variable</span>
  <span class="hljs-built_in">int</span> counter = <span class="hljs-number">0</span>;
  <span class="hljs-comment">// Special function to create/get object of instance</span>
  <span class="hljs-keyword">static</span> ExampleA getInstance(){
  }
}
</code></pre>
</li>
<li><p>We need to create a static variable which will store instances of objects of their own class.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExampleA</span></span>{
  <span class="hljs-comment">// Static variable</span>
  <span class="hljs-keyword">static</span> ExampleA instance;
  <span class="hljs-comment">// Class variable</span>
  <span class="hljs-built_in">int</span> counter = <span class="hljs-number">0</span>;   
  <span class="hljs-comment">// Special function to create/get object of instance</span>
  <span class="hljs-keyword">static</span> ExampleA getInstance(){
  }
}
</code></pre>
</li>
<li><p>But we don't want to create an instance of an object if it does not need anywhere in our program.</p>
<pre><code class="lang-dart">  <span class="hljs-comment">// Static variable</span>
  <span class="hljs-keyword">static</span> ExampleA instance = <span class="hljs-keyword">null</span>;
</code></pre>
</li>
<li><p>Now, we came to the main part, designing the <em>getInstance</em> static function. In this function, we will return the instance of already existing object. If no object currently available, we will create</p>
</li>
</ul>
<p><strong><em>Kindly see the comments of the code to understand</em></strong></p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExampleA</span></span>{
  <span class="hljs-comment">// Static variable</span>
  <span class="hljs-keyword">static</span> ExampleA instance = <span class="hljs-keyword">null</span>;
  <span class="hljs-comment">// Class variable</span>
  <span class="hljs-built_in">int</span> counter = <span class="hljs-number">0</span>;
  <span class="hljs-comment">// Special function to create/get the object of instance</span>
  <span class="hljs-keyword">static</span> ExampleA getInstance(){
    <span class="hljs-comment">// If no instance has already created, create a new one and assign it to an instance variable </span>
    <span class="hljs-keyword">if</span>(instance == <span class="hljs-keyword">null</span>) instance = ExampleA();
    <span class="hljs-keyword">return</span> instance;
  }
}
</code></pre>
<ul>
<li>That's All 🎉🎉</li>
</ul>
<h2 id="heading-lets-implement-the-logic-in-java-andamp-run">Let's implement the logic in Java &amp; Run</h2>
<p>Code -</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExampleA</span></span>{
    <span class="hljs-keyword">static</span> ExampleA instance;
    <span class="hljs-keyword">int</span> counter = <span class="hljs-number">0</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ExampleA <span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span>{
        <span class="hljs-keyword">if</span>(instance == <span class="hljs-keyword">null</span>){
            instance = <span class="hljs-keyword">new</span> ExampleA();
        }
        <span class="hljs-keyword">return</span> instance;
    }
}
</code></pre>
<p>Write little bit driver code to test -</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">testProgram</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        ExampleA object1 = ExampleA.getInstance();
        object1.counter++;

        ExampleA object2 = ExampleA.getInstance();
        object2.counter++;

        System.out.println(object2.counter);
    }    
}
</code></pre>
<p><em>Let's run the program</em> By <strong>object1.counter++</strong>, the counter goes from 0 to 1. As the object2 is the same instance, by <strong>object2.counter++</strong>, the counter goes from 1 to 2.</p>
<p>Output -</p>
<pre><code class="lang-java"><span class="hljs-number">2</span>
</code></pre>
<p>🏊🏊 Nice, our output comes perfect, which means now in the program, where I want the object, I can simply call <strong><em>ExampleA.getInstance()</em></strong>, and access the function and values of the object.</p>
<h2 id="heading-best-practice">Best Practice</h2>
<p>If the language has concept of public and private methods of class, make sure to make the default constructor to private.</p>
<h2 id="heading-whats-your-task">What's your task?</h2>
<p>If you leave this after understanding, you gonna face issues..Better write a Singleton Class in your favourite language and post it in a comment for a reference for others.</p>
<p><strong><em>Thank You 👼👼</em></strong></p>
<p><em>Any issue, comment down</em></p>
]]></content:encoded></item><item><title><![CDATA[FlushMail - Anonymous Temporary Mail Service [Support files/attachment and immediate mail disposal]]]></title><description><![CDATA[Recently I got interested in the mailing system and explored some stuff, and finally decided to design a Temporary E-mail service as my first work in mailing service.
FlushMail - Anonymous Temporary Mail Service [Support files/attachment and immediat...]]></description><link>https://blog.tanmoysrt.xyz/flushmail-anonymous-temporary-mail-service-support-filesattachment-and-immediate-mail-disposal</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/flushmail-anonymous-temporary-mail-service-support-filesattachment-and-immediate-mail-disposal</guid><category><![CDATA[Temporay Mail]]></category><category><![CDATA[Mail]]></category><category><![CDATA[Developer]]></category><category><![CDATA[development]]></category><category><![CDATA[Contribution & Impact]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sun, 20 Nov 2022 11:27:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668943497968/UVsOC7bZ1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently I got interested in the mailing system and explored some stuff, and finally decided to design a Temporary E-mail service as my first work in mailing service.</p>
<p><strong><em>FlushMail - Anonymous Temporary Mail Service [Support files/attachment and immediate mail disposal]</em></strong></p>
<p>You can access this here: https://flushmail.live and the link in the first comment.</p>
<p>Please leave feedback in the comments.
If you would like a detailed blog on this project/mailing system or any other topic, feel free to let me know in the comment section.</p>
<p>I am working on its documentation part, ASAP it gets ready I will update that. I am going to extend this one project and have some ideas to work on an email privacy tool. If anyone want to collaborate please give a reply</p>
]]></content:encoded></item><item><title><![CDATA[How to claim 🤫 1000 Dollars Of Free Credit from AWS?]]></title><description><![CDATA[If you are building a tech product for your startup or for others [Social work], and if you are thinking about the cost of maintenance of cloud and hosting, then the AWS Activate program is here to help you.
You can host your product at Zero Cost.
AW...]]></description><link>https://blog.tanmoysrt.xyz/how-to-claim-1000-dollars-of-free-credit-from-aws</link><guid isPermaLink="true">https://blog.tanmoysrt.xyz/how-to-claim-1000-dollars-of-free-credit-from-aws</guid><category><![CDATA[AWS Activate]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Startups]]></category><category><![CDATA[tech startup]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Tanmoy Sarkar]]></dc:creator><pubDate>Sat, 05 Nov 2022 13:58:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1667579301115/NfcP5N6vA.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you are building a <strong>tech product for your startup or for others [Social work]</strong>, and if you are thinking about the cost of maintenance of cloud and hosting, then the AWS Activate program is here to help you.</p>
<p>You can host your product at <strong>Zero Cost</strong>.</p>
<p><strong>AWS Activate</strong> program helps to begin your tech startup journey at zero cost by providing 1000 dollars worth of credit for 2 years of validity.</p>
<p>You can visit <a target="_blank" href="https://aws.amazon.com/activate/">AWS Activate</a> for more details.</p>
<p><strong>Eligibility Criteria</strong></p>
<ul>
<li></li>
<li>You must have a domain name in the name of your product/startup. You can purchase one at <a target="_blank" href="https://www.godaddy.com/">Godaddy</a></li>
<li>You need to set up a plain landing page with the details<ul>
<li>Few lines of description about your product/project</li>
<li>What is the USP? [In simple terms, what is the need for your product]</li>
<li>Provide contact details in the footer</li>
</ul>
</li>
</ul>
<p><strong>That's all !</strong></p>
<p><strong>Steps to claim credit</strong></p>
<ul>
<li>Build a landing page from HTML Templates or by any drag-and-drop tool like <a target="_blank" href="https://www.wix.com/">Wix</a>. <em>If you have already skipped this step</em>.</li>
<li>Purchase one domain from <a target="_blank" href="https://www.godaddy.com/">Godaddy</a>, if you haven't.</li>
<li>Host the website. If you want to host it free of cost, host it in GitHub by <em>Github pages</em>. You can watch this video on how to host a simple website on GitHub pages. <a target="_blank" href="https://youtu.be/A2R-CMMyp64">youtu.be/A2R-CMMyp64</a></li>
<li>Now you are ready to apply.</li>
<li>Go to <a target="_blank" href="https://aws.amazon.com/activate/">aws.amazon.com/activate/</a> and Click on  <em>Join Now</em>.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667642181944/-th0nmTNi.png" alt="image.png" class="image--center mx-auto" /></li>
</ul>
<blockquote>
<p>You may be asked for login. If you haven't an account just create one, AWS has no requirement for a credit card, You can verify the account by providing a debit card, and also AWS doesn't charge automatically from the card. That's a good thing about AWS.</p>
</blockquote>
<ul>
<li><p>Provide the details. If you haven't any startup name, just put your product name in the <em>Company Name</em> field and your residence address in <em>Company Address</em>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667642133941/Bm65noU_6.png" alt="Screenshot from 2022-11-04 22-43-28.png" class="image--center mx-auto" /></p>
</li>
<li><p>On the next page provide your team details. <em>Must provide Linkedin Profile although it's an optional field. It proves the authenticity of the team members</em>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667642147780/2YkQGUWKH.png" alt="Screenshot from 2022-11-04 22-43-55.png" class="image--center mx-auto" /></p>
</li>
<li><p>On the next page it will ask for your <em>Product Details</em>.</p>
<ul>
<li>Try to brief and point answers to the questions</li>
<li>Provide a link to the landing page</li>
<li>If you have any product demos, try to provide a link to product details. It will lead to quick approval.</li>
</ul>
</li>
<li><p><em>You are done !</em></p>
</li>
<li>Expect to get the mail of approval within 7~14 days. </li>
</ul>
<p><strong><em>If you are interested in software development and technology, <a target="_blank" href="https://tanmoy.codes/newsletter">add your e-mail to the newsletter</a> so that whenever I publish a new blog you will get instant alerts</em></strong></p>
]]></content:encoded></item></channel></rss>