<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  
    <title type="text" xml:lang="en">Shekhar Singh - Tech, Data, Fitness, Books - rootcss</title>
    <link type="application/atom+xml" rel="self" href="https://shekharsingh.com//atom.xml"/>
  
  <link href="https://shekharsingh.com//"/>
  <id>https://shekharsingh.com//</id>
  <updated>2022-08-02T18:35:29Z</updated>
  <author>
    <name>Shekhar Singh</name>
    <email>shekhar [.] singh [@] msn [.] com</email>
  </author>
  <rights type="text">Copyright © 2022 Shekhar Singh. All rights reserved.</rights>
  
  <entry>
  <title type="text">Notes - How to gracefully say No</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2020/10/03/how-to-gracefully-say-no.html" />
  <id>https://shekharsingh.com//blog/2020/10/03/how-to-gracefully-say-no</id>
  <published>2020-10-03T00:00:00Z</published>
  <updated>2020-10-03T00:00:00Z</updated>
  <content type="html"><![CDATA[ <p>When we have strong internal clarity it is almost as if we have a force field protecting us from the nonessentials coming at us from all directions.</p>

<p>Non-Essentialist:</p>
<ul>
  <li>Avoids saying no to avoid feeling social awkwardness and pressure</li>
  <li>Says yes to everything</li>
</ul>

<p>Essentialist:</p>
<ul>
  <li>Dares to say no firmly, resolutely, and gracefully</li>
  <li>Says yes only to the things that really matter</li>
</ul>

<p><br />
<strong>Guidelines for delivering the graceful no</strong></p>

<ul>
  <li>Separate the decision from the relationship</li>
  <li>Saying no gracefully doesn’t have to mean using the word “no”</li>
  <li>Focus on the trade-off</li>
  <li>Remind yourself that everyone is selling something</li>
  <li>Make your peace with the fact that saying no often requires <i>trading popularity for respect</i></li>
  <li>Remember that a clear no can be more graceful than a vague or non-committal yes</li>
</ul>

<p><br />
<strong>The No Repertoire</strong></p>

<p>Essentialists don’t say no just occasionally. It is a part of their regular repertoire. To consistently say no with grace, it helps to have a variety of responses to call upon. Below are eight responses you can put in your no repertoire:</p>

<ul>
  <li>The awkward pause</li>
  <li>The soft no (or the no but)</li>
  <li>Let me check my calendar and get back to you.</li>
  <li>Use e-mail bouncebacks.</li>
  <li>Say, Yes. What should I deprioritize?</li>
  <li>Say it with humor.</li>
  <li>Use the words You are welcome to X. I am willing to Y.</li>
  <li>I can’t do it, but X might be interested.</li>
</ul>

<p><br />
<strong>Credits</strong>:</p>

<p>These notes are from the book <strong>Essentialism: The Disciplined Pursuit of Less</strong> by Greg McKeown (Chapter #11)</p>

<p><br />
<strong>Disclaimer</strong>:</p>

<p>These notes might be very contextual if you haven’t read the book.</p>
 ]]></content>
</entry>


  <entry>
  <title type="text">Notes - How to avoid commitment traps</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2020/10/03/how-to-avoid-the-commitment-traps.html" />
  <id>https://shekharsingh.com//blog/2020/10/03/how-to-avoid-the-commitment-traps</id>
  <published>2020-10-03T00:00:00Z</published>
  <updated>2020-10-03T00:00:00Z</updated>
  <content type="html"><![CDATA[ <ol>
  <li>Beware of the endowment effect
    <ul>
      <li><strong>the endowment effect</strong>: our tendency to undervalue things that aren’t ours and to overvalue things because we already own them.</li>
    </ul>
  </li>
  <li>
    <p>Pretend you don’t own it yet</p>
  </li>
  <li>
    <p>Get over the fear of waste</p>
  </li>
  <li>
    <p>Admit failure to begin success</p>
  </li>
  <li>
    <p>Stop trying to force a fit</p>
  </li>
  <li>
    <p>Get a neutral second opinion</p>
  </li>
  <li>Be aware of the status quo bias
    <ul>
      <li>The tendency to continue doing something simply because we have always done it is sometimes called the <strong>status quo bias</strong>.</li>
    </ul>
  </li>
  <li>Apply zero-based budgeting
    <ul>
      <li><strong>zero-based budgeting</strong>: instead of trying to budget your time on the basis of existing commitments, assume that all bets are off. All previous commitments are gone. Then begin from scratch, asking which you would add today.</li>
    </ul>
  </li>
  <li>
    <p>Stop making casual commitments</p>
  </li>
  <li>
    <p>From now on, pause before you speak</p>
  </li>
  <li>
    <p>Get over the fear of missing out</p>
  </li>
  <li>To fight this fear, run a reverse pilot
    <ul>
      <li>In a <strong>reverse pilot</strong>, you test whether removing an initiative or activity will have any negative consequences.</li>
    </ul>
  </li>
</ol>

<p><br />
<strong>Credits</strong>:</p>

<p>These notes are from the book <strong>Essentialism: The Disciplined Pursuit of Less</strong> by Greg McKeown (Chapter #12)</p>

<p><br />
<strong>Disclaimer</strong>:</p>

<p>These notes might be very contextual if you haven’t read the book.</p>
 ]]></content>
</entry>


  <entry>
  <title type="text">How We Monitor Apache Airflow in Production at Gojek</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2020/05/20/how-we-monitor-apache-airflow-in-production-at-gojek.html" />
  <id>https://shekharsingh.com//blog/2020/05/20/how-we-monitor-apache-airflow-in-production-at-gojek</id>
  <published>2020-05-20T00:00:00Z</published>
  <updated>2020-05-20T00:00:00Z</updated>
  <content type="html"><![CDATA[ <p>This post was orignially posted <a target="_blank" href="https://blog.gojekengineering.com/how-we-monitor-apache-airflow-in-production-210f9bff9e71">here</a> in <b>Gojek Engineering Blog</b>. (I work at <a target="_blank" href="https://www.gojek.com/">Gojek</a>)</p>
<hr />

<p>A quick guide on what (and how) to monitor to keep your workflows running
smoothly.</p>

<p><img class="img-responsive" src="https://shekharsingh.com//assets/images/airflow_gojek/cover.jpeg" alt="Pandas memory leak" /></p>

<p>If your organisation deals with a significant amount of data and has huge data
pipelines, chances are you must have used or heard about Apache Airflow already.
Airflow is an open-source workflow management platform that enables scheduling
and monitoring workflows programmatically.</p>

<p>At Gojek, our products generate a tremendous amount of data, but that’s only
step one. We’re constantly making use of that data and give value back to our
customers, merchants, and partners — in the form of recommendations and other
customisations. The ‘Data Engineering’ (DE) Team is responsible for building the
platform and products to manage the entire lifecycle of data.</p>

<p>Needless to say, Airflow is one of our most heavily used tools. We cater over a
thousand pipelines and an enormous amount of data using Airflow. Monitoring all
these pipelines is not easy — especially considering that Airflow is still in
its early phase.</p>

<p>Like any production application, it becomes crucial to monitor the Airflow jobs
and of course, Airflow itself. It has a very resilient architecture and the
design is highly scalable. It has multiple components to enable this, viz.
Scheduler, Webserver, Workers, Executor, and so on. At Gojek, we have a few
additional processes as well to enable flexibility for our workflows.</p>

<p>For example, we have a separate process running to sync our DAGs with GCS/git
and a separate process to sync custom Airflow variables. We know very well that,
<strong>the more components you have, higher the chances of failure.</strong> Hence, this
requires a thorough monitoring and alerting system.</p>

<p><img class="img-responsive" src="https://shekharsingh.com//assets/images/airflow_gojek/dash1.png" />
<center><span style="font-size:12px; colore:#ccc;">A snapshot of the dashboard in a dummy environment</span></center>
</p>

<h3 id="high-level-architecture">High-level architecture</h3>

<p>At a high-level, we have multiple Airflow processes running in our different
Kubernetes Pods, and each of them has a statsd client enabled using
<em>airflow.cfg</em>. The statsd client will send all the metrics to Telegraf over UDP.
Our custom processes are also emitting those heartbeats and other data in the
same way.</p>

<p><img class="img-responsive" src="https://shekharsingh.com//assets/images/airflow_gojek/architecture.png" />
<center><span style="font-size:12px; colore:#ccc;">Airflow Monitoring — High-Level Architecture</span></center>
</p>

<p>We’ve configured InfluxDB as an output for Telegraf configuration
(<em>telegraf.conf</em>) which will send the data over HTTP. You can add InfluxDB as a
data source in Grafana as well as in Kapacitor. The alerts can now be configured
in Kapacitor using TICK scripts which we’ll cover in the next sections.</p>

<h3 id="understanding-airflow-statsd-metrics">Understanding Airflow statsd metrics</h3>

<p>Airflow’s implementation and documentation of metrics are not the best things
about it and it’s still in the early stages. In the first attempt, the
measurements created by Airflow in InfluxDB were not how we wanted them to be.
We solved that by writing some custom statsd telegraf templates based on the
metrics name. Some of them are:</p>

<p>
<script src="https://gist.github.com/rootcss/0a3a7ea05da3a90f624380d181e50b5c.js"></script>
<center><span style="font-size:12px; colore:#ccc;">Sample statsd templates for telegraf.conf</span></center>
</p>

<p>These templates will create some meaningful measurements named
<em>prefix_dag_duration</em>, <em>prefix_dagrun_schedule_delay</em>,
<em>prefix_dag_loading-duration,</em> etc in InfluxDB which can be easily queried using
Grafana/Kapacitor. Following is a sample of how the fields (or tags) are parsed
in InfluxDB:</p>

<p>
<script src="https://gist.github.com/rootcss/5035685ab9b1541214fd0468659e0897.js"></script>
<center><span style="font-size:12px; colore:#ccc;">Sample influx measurements schema after being processed by our templates</span></center>
</p>

<p>The tags enable higher flexibility for querying and filtering the data. We built
a Grafana dashboard on top of it as the first goal to see what’s happening
under-the-hood. A sample query to generate a time series trend in Grafana for
the above measurement is:</p>
<p>
<script src="https://gist.github.com/rootcss/f57fdcad7a0b553a5b47287f7c0f9274.js"></script>
<center><span style="font-size:12px; colore:#ccc;">Sample Grafana query to fetch data from Influx</span></center>
</p>

<h3 id="what-should-you-monitor">What should you monitor?</h3>

<p>The following list contains some of the important areas that you should monitor,
which could also be helpful for debugging and finding bottlenecks for resources:</p>

<ul>
  <li>Health checks: Are scheduler, webserver, workers, and other custom processes
running? What’s their uptime?</li>
  <li>How many workers are running?</li>
  <li>Are our custom metrics and configurations being reflected in metrics?</li>
  <li>Number of active DAGs, and DAG parsing time</li>
  <li>Trend: Pools usage</li>
  <li>Trend: Jobs execution status (started/ended)</li>
  <li>Trend: Executor tasks status (running/queued/open slots)</li>
  <li>Trend: Operator-wise execution status (failure/success)</li>
  <li>Trend: Task Instances status (successes/failures)</li>
  <li>Trend: Time taken by crucial tasks, sensors</li>
  <li>Trend: Time taken by the DAGs before coming to an end state</li>
  <li>Trend: Schedule Delay of DAGs</li>
  <li>Trend: Time spent by DAGs for completing dependency checks</li>
</ul>

<p>It’s important to track these metrics at an overall level, as well as individual
tasks and the DAG level. You should also consider tracking your specific
operators and tasks that you think have higher chances of failure and/or consume
more resources.</p>

<p><img class="img-responsive" src="https://shekharsingh.com//assets/images/airflow_gojek/dash2.png" />
<center><span style="font-size:12px; colore:#ccc;">A snapshot of the dashboard in a dummy environment</span></center>
</p>

<h3 id="alerting">Alerting</h3>

<p>Now that we have data in InfluxDB, and the monitoring is in place, we can use
Kapacitor to write the TICK script to trigger alerts based on the checks and
thresholds. The following snippets show some sample alerts that can be set.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// alert if scheduler is down.</span>
<span class="nx">stream</span>
    <span class="o">|</span><span class="k">from</span><span class="p">()</span>
        <span class="p">.</span><span class="nx">measurement</span><span class="p">(</span><span class="dl">'</span><span class="s1">prefix_scheduler_heartbeat</span><span class="dl">'</span><span class="p">)</span>
    <span class="o">|</span><span class="nx">deadman</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mi">5</span><span class="nx">m</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">id</span><span class="p">(</span><span class="dl">'</span><span class="s1">AirflowSchedulerDown</span><span class="dl">'</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">message</span><span class="p">(</span><span class="dl">'</span><span class="s1">Airflow Scheduler is down</span><span class="dl">'</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">/tmp/alert_logs.txt</span><span class="dl">'</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">trigger_alert_method</span><span class="p">()</span>

<span class="c1">// alert if worker count does not match the required value</span>
<span class="nx">stream</span>
    <span class="o">|</span><span class="k">from</span><span class="p">()</span>
        <span class="p">.</span><span class="nx">measurement</span><span class="p">(</span><span class="dl">'</span><span class="s1">prefix_celery_workers</span><span class="dl">'</span><span class="p">)</span>
    <span class="o">|</span><span class="nb">window</span><span class="p">()</span>
        <span class="p">.</span><span class="nx">period</span><span class="p">(</span><span class="mi">5</span><span class="nx">m</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">every</span><span class="p">(</span><span class="mi">5</span><span class="nx">m</span><span class="p">)</span>
    <span class="o">|</span><span class="nx">alert</span><span class="p">()</span>
        <span class="p">.</span><span class="nx">id</span><span class="p">(</span><span class="dl">'</span><span class="s1">Celery Workers Count</span><span class="dl">'</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">crit</span><span class="p">(</span><span class="nx">lambda</span><span class="p">:</span> <span class="dl">"</span><span class="s2">value</span><span class="dl">"</span> <span class="o">&lt;=</span> <span class="mi">2</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="nx">lambda</span><span class="p">:</span> <span class="dl">"</span><span class="s2">value</span><span class="dl">"</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">/tmp/alert_2.txt</span><span class="dl">'</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">trigger_alert_method</span><span class="p">()</span>
</code></pre></div></div>

<p>Apart from this, it is also important to monitor the health of InfluxDB,
Kapacitor, and Grafana as well.</p>

<h3 id="references">References</h3>

<ul>
  <li><a href="https://airflow.apache.org/docs/stable/metrics.html">https://airflow.apache.org/docs/stable/metrics.html</a></li>
  <li><a href="https://docs.influxdata.com/kapacitor/v1.5/tick/introduction/">https://docs.influxdata.com/kapacitor/v1.5/tick/introduction/</a></li>
</ul>

<p>Thank you, everyone, at the DE team — we build and manage the components
described above, and special thanks to
<a href="https://twitter.com/sravankorumilli">Sravan</a> for the discussions and pairing.
If you’ve questions, let us know in the comments or <a href="https://twitter.com/rootcss">tweet
me</a>.</p>

<hr />

<p>Liked what you read? Get our stories delivered straight to your inbox by
<a href="https://mailchi.mp/go-jek/gojek-tech-newsletter">signing up for Gojek newsletter</a>. 🖖</p>
 ]]></content>
</entry>


  <entry>
  <title type="text">List of a few cycling trips</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2020/04/27/list-of-cycling-trips.html" />
  <id>https://shekharsingh.com//blog/2020/04/27/list-of-cycling-trips</id>
  <published>2020-04-27T00:00:00Z</published>
  <updated>2020-04-27T00:00:00Z</updated>
  <content type="html"><![CDATA[ <iframe src="https://www.google.com/maps/d/u/0/embed?mid=1D3DYBDKmwsMhfCCjoSAf4PQEV-rXH_GA" width="800" height="480" frameborder="0">
</iframe>
<p><br /></p>
<ul>
    <li>[430+ km] Mangalore to Panjim, Goa - 05/10/2019 with Parkar</li>
    <li>[60 km] Hennur Bamboo Forest - 29/09/2019 - with Parkar</li>
    <li>[240 km] Kolar, Avani - 240 km in 11 hour - 15/08/2019 - solo</li>
    <li>[130 km] Big Banayan Tree, Machanbele, Savandurga Hills  - 13/01/2019 - with Parkar</li>
    <li>[80 km] Hesaraghatta Lake - 25/12/2017 with Parkar</li>
    <li>[335 km] Bangalore-Sakleshpur-Chikmangaluru - 10/2017 with Parkar</li>
    <li>[128 km] Nandi Hills - 17/09/2017 with Parkar</li>
    <li>[70 km] Mysore Trip</li>
</ul>
 ]]></content>
</entry>


  <entry>
  <title type="text">Deploying a service on Kubernetes locally using Terraform</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2020/04/19/deploying-a-service-on-kubernetes-locally-using-terraform.html" />
  <id>https://shekharsingh.com//blog/2020/04/19/deploying-a-service-on-kubernetes-locally-using-terraform</id>
  <published>2020-04-19T00:00:00Z</published>
  <updated>2020-04-19T00:00:00Z</updated>
  <content type="html"><![CDATA[ <p>A couple of weeks back, I was trying to debug a Helm chart, but wasn’t able to iterate and test the changes as fast as I wanted to. In such situation, I always prefer to test things on my own setup (usually on local machine) - for which I needed Kubernetes locally too. When I started installing minikube using official documentation, it didn’t work in my first attempt because of a couple of errors related to Hypervisor and Virtualbox. Also, my debugging required me to use terarform and a custom application, hence this blog post :)</p>

<p>In this post, we’ll deploy a small Go service on Kubernetes using Terraform, locally.</p>

<p>Versions:</p>
<div class="language-config highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">MacOS</span>: <span class="m">10</span>.<span class="m">15</span>.<span class="m">4</span>
<span class="n">docker</span>: <span class="m">19</span>.<span class="m">03</span>.<span class="m">8</span>
<span class="n">kubectl</span>: <span class="n">client</span> <span class="n">v1</span>.<span class="m">15</span>.<span class="m">5</span>, <span class="n">server</span> <span class="n">v1</span>.<span class="m">14</span>.<span class="m">10</span>-<span class="n">gke</span>.<span class="m">17</span>
<span class="n">go</span>: <span class="m">1</span>.<span class="m">13</span>.<span class="m">9</span>
<span class="n">minikube</span>: <span class="n">v1</span>.<span class="m">9</span>.<span class="m">2</span>
<span class="n">terraform</span>: <span class="n">v0</span>.<span class="m">12</span>.<span class="m">24</span>
</code></pre></div></div>

<p>You can install <a target="_blank" href="https://www.docker.com/products/docker-desktop">docker</a> and <a target="_blank" href="https://kubernetes.io/docs/tasks/tools/install-kubectl/">kubectl</a> first.</p>

<h2 id="installing-minikube">Installing Minikube</h2>
<p>Minikube helps us run a single-node Kubernetes cluster locally. You can go through full installation details <a target="_blank" href="https://kubernetes.io/docs/tasks/tools/install-minikube/">here</a>. The prerequisite to run minikube is a hypervisor for your system. Most modern systems have virtualization enabled by default, which you can verify using this command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># for macOS</span>
<span class="nv">$ </span>sysctl <span class="nt">-a</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="nt">--color</span> <span class="s1">'machdep.cpu.features|VMX'</span>
</code></pre></div></div>
<p>If you see VMX highlighted in the output, it’s enabled for you. Hypervisor is the software that lets you run VM on an existing system. We’re going to use <a href="https://github.com/moby/hyperkit" target="_blank">hyperkit</a> - which is lightweight and not from Oracle 😛</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install hyperkit</span>
<span class="nv">$ </span>brew <span class="nb">install </span>hyperkit
<span class="c"># Install minikube</span>
<span class="nv">$ </span>brew <span class="nb">install </span>minikube
<span class="c"># Start minikube with hyperkit</span>
<span class="nv">$ </span>minikube start <span class="nt">--vm-driver</span><span class="o">=</span>hyperkit
<span class="c"># Start minikube dashboard</span>
<span class="nv">$ </span>minikube dashboard
</code></pre></div></div>

<p><img class="img-responsive" src="https://shekharsingh.com//assets/images/k8s-dashboard.png" alt="k8s dashboard" /></p>

<p>Minikube has an isolated docker environment other than the one installed by docker. To switch to that environment, use following command. All the next commands in this shell will be run on minikube docker environment.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">eval</span> <span class="si">$(</span>minikube <span class="nt">-p</span> minikube docker-env<span class="si">)</span>
</code></pre></div></div>

<h2 id="building-a-small-service">Building a small service</h2>
<p>We’ll now quickly build a small Go application and dockerize it.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># your directory structure will look like this</span>
<span class="nv">$ </span>tree myapp
myapp
├── Dockerfile
├── Makefile
└── myapp.go
</code></pre></div></div>
<p>myapp.go</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"fmt"</span>
	<span class="s">"net/http"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/"</span><span class="p">,</span> <span class="n">HelloServer</span><span class="p">)</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Starting server on localhost:8080"</span><span class="p">)</span>
	<span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">HelloServer</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">fmt</span><span class="o">.</span><span class="n">Fprintf</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="s">"Hello, %s!"</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Path</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="p">])</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Makefile</p>
<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">NAME</span><span class="o">=</span>myapp
<span class="nv">VERSION</span><span class="o">=</span>0.1
<span class="nl">all</span><span class="o">:</span> <span class="nf">build</span>
<span class="nl">build</span><span class="o">:</span> <span class="nf">go build -ldflags "-X main.Version=${VERSION}" myapp.go</span>
</code></pre></div></div>

<p>Dockerfile</p>
<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="s"> golang:1.13-stretch as base</span>
<span class="k">WORKDIR</span><span class="s"> /build/</span>
<span class="k">COPY</span><span class="s"> . .</span>
<span class="k">RUN </span><span class="o">[</span><span class="s2">"make"</span><span class="o">]</span>

<span class="k">FROM</span><span class="s"> alpine:latest</span>
<span class="k">WORKDIR</span><span class="s"> /opt/myapp</span>
<span class="k">COPY</span><span class="s"> --from=base /build/myapp /opt/myapp/bin/myapp</span>
<span class="k">RUN </span><span class="o">[</span><span class="s2">"apk"</span>, <span class="s2">"update"</span><span class="o">]</span>
<span class="k">EXPOSE</span><span class="s"> 8080</span>

<span class="k">RUN </span><span class="o">[</span><span class="s2">"apk"</span>, <span class="s2">"add"</span>, <span class="s2">"libc6-compat"</span><span class="o">]</span>
<span class="k">ENTRYPOINT</span><span class="s"> ["/opt/myapp/bin/myapp"]</span>
</code></pre></div></div>

<p>Build and start your container using following commands (you already know these):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>docker build <span class="nt">-t</span> myapp:0.1 <span class="nb">.</span>
<span class="nv">$ </span>docker run <span class="nt">-p</span> 8080:8080 myapp:0.1
Starting server on localhost:8080

<span class="nv">$ </span>curl localhost:8080
Hello, <span class="o">!</span>
<span class="c"># our app is working fine.</span>
</code></pre></div></div>
<p>Now, we’ll finally write our terraform scripts to deploy this service on minikube.</p>

<h2 id="writing-the-terraform-script">Writing the Terraform script</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># here are the files that we're going to create</span>
<span class="nv">$ </span>tree deploy
deploy
├── main.tf
└── outputs.tf
</code></pre></div></div>
<p>main.tf</p>
<div class="language-terraform highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">provider</span> <span class="s2">"kubernetes"</span> <span class="p">{</span>
  <span class="nx">config_context_cluster</span>   <span class="p">=</span> <span class="s2">"minikube"</span>
<span class="p">}</span>

<span class="c1"># In kubernetes, you can deploy with different type of objects</span>
<span class="c1"># like, Pod, ReplicationController, Deployment etc.</span>
<span class="c1"># While Deployment is highly recommended for production use-cases, </span>
<span class="c1"># we'll simply use Pod object</span>
<span class="k">resource</span> <span class="s2">"kubernetes_pod"</span> <span class="s2">"myapp"</span> <span class="p">{</span>
  <span class="nx">metadata</span> <span class="p">{</span>
    <span class="nx">name</span> <span class="p">=</span> <span class="s2">"myapp"</span>
    <span class="nx">labels</span> <span class="p">=</span> <span class="p">{</span>
      <span class="nx">App</span> <span class="p">=</span> <span class="s2">"myapp"</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="nx">spec</span> <span class="p">{</span>
    <span class="nx">container</span> <span class="p">{</span>
      <span class="nx">image</span> <span class="p">=</span> <span class="s2">"myapp:0.1"</span>
      <span class="nx">name</span>  <span class="p">=</span> <span class="s2">"myapp"</span>

      <span class="nx">port</span> <span class="p">{</span>
        <span class="nx">container_port</span> <span class="p">=</span> <span class="mi">8080</span>
      <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="c1"># Let's create a Service object - in simple words, this object helps</span>
<span class="c1"># you with loadbalancing and network abstraction on top of pods</span>
<span class="k">resource</span> <span class="s2">"kubernetes_service"</span> <span class="s2">"myapp"</span> <span class="p">{</span>
  <span class="nx">metadata</span> <span class="p">{</span>
    <span class="nx">name</span> <span class="p">=</span> <span class="s2">"myapp"</span>
  <span class="p">}</span>
  <span class="nx">spec</span> <span class="p">{</span>
    <span class="nx">selector</span> <span class="p">=</span> <span class="p">{</span>
        <span class="nx">App</span> <span class="p">=</span> <span class="nx">kubernetes_pod</span><span class="p">.</span><span class="nx">myapp</span><span class="p">.</span><span class="nx">metadata</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">labels</span><span class="p">.</span><span class="nx">App</span>
    <span class="p">}</span>
    <span class="nx">port</span> <span class="p">{</span>
      <span class="nx">port</span>        <span class="p">=</span> <span class="mi">80</span>
      <span class="nx">target_port</span> <span class="p">=</span> <span class="mi">8080</span>
    <span class="p">}</span>

    <span class="nx">type</span> <span class="p">=</span> <span class="s2">"NodePort"</span> <span class="c1">#"LoadBalancer"</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>outputs.tf</p>
<div class="language-terraform highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">output</span> <span class="s2">"name"</span> <span class="p">{</span>
  <span class="nx">value</span> <span class="p">=</span> <span class="s2">"</span><span class="k">${</span><span class="nx">kubernetes_pod</span><span class="p">.</span><span class="nx">myapp</span><span class="p">.</span><span class="nx">metadata</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">name</span><span class="k">}</span><span class="s2">"</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="applying-our-infrastructure">Applying our Infrastructure</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cd </span>deploy
<span class="nv">$ </span>terraform init
<span class="nv">$ </span>terraform apply
</code></pre></div></div>

<p>At this point, the service should be up and running. You can verify the pods and their status. To get the IP of your service, use the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>minikube service myapp 
<span class="c"># this will open up your service in the brwoser window</span>
</code></pre></div></div>

<p><br />
In the next post, I’ll try to post about the minor issue I was facing in helm charts, that I was able to reproduce in local and finally fix it :)</p>
 ]]></content>
</entry>


  <entry>
  <title type="text">Running - The Bangalore airport solo Half Marathon 2019 - 26 km</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2019/12/22/running-the-bangalore-airport-solo-half-marathon-26-km.html" />
  <id>https://shekharsingh.com//blog/2019/12/22/running-the-bangalore-airport-solo-half-marathon-26-km</id>
  <published>2019-12-22T00:00:00Z</published>
  <updated>2019-12-22T00:00:00Z</updated>
  <content type="html"><![CDATA[ <p>
The Airport Run 2019 (third). This one was tougher than last year, probably because I weigh 5kg+ (planned weight gain) more since then, which I could clearly feel. They've dug a long part of the airport road, so the track is not as good now.
</p>
<p>
The shoes is the picture is now finally retired, which I used for 3 years and all the Airport runs as well. Atleast <b>2100 km</b> of running in these shoes overall.
So far I've been successful in running a half marathon (+ 5 km) airport run on last Sunday of every year for 3 consecutive years. I plan on continuing this. I ran today because of some plans on next Sunday (actual last)
</p>
<p><br /></p>
<center><img class="img-responsive" src="https://shekharsingh.com//assets/images/airport_run_2019.png" alt="airport_run_2019" style="width:500px;height:500px;" />
</center>
 ]]></content>
</entry>


  <entry>
  <title type="text">Cycling Trip - Mangalore to Goa across the diverse Indian west coast - 430+ km</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2019/10/07/cycling-trip-mangalore-to-panjim-goa-430-km.html" />
  <id>https://shekharsingh.com//blog/2019/10/07/cycling-trip-mangalore-to-panjim-goa-430-km</id>
  <published>2019-10-07T00:00:00Z</published>
  <updated>2019-10-07T00:00:00Z</updated>
  <content type="html"><![CDATA[ <ul>
	<li><a href="#section_1">Day 0: Finding the bus to Mangalore in heavy rains (with our bikes)</a></li>
	<li><a href="#section_2">Day 1: Mangalore to Malpe Beach, Udupi, St. Mary's Island</a></li>
	<li><a href="#section_3">Day 2: Murdeshwar</a></li>
	<li><a href="#section_4">Day 3: Gokarna</a></li>
	<li><a href="#section_5">Day 4: Karwar, Polem, Palolem</a></li>
	<li><a href="#section_6">Day 5: Agonda, Cola, Panjim to Bangalore</a></li>
</ul>

<center><img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/mangalore_goa/cover.jpg" style="width:700px;height:450px;" /></center>

<p><br />
<span style="color: #888;"><i>Note: The post is slightly detailed. I wanted to keep it detailed because it’s fun to read it later. This trip took place from 01-10-2019 onwards, and I started writing this post on 7th Oct, but got it finished on 26th April.</i></span></p>

<hr />

<p>I often open up Google Maps, and search for the places/routes to visit next. India’s west coast has always been in my mind. This route consisted of many good places I always liked, plus, our Bangalore-Sakleshpur-Chikamangalur trip had the Mangalore highway in 70% of the trip; which always kept me keen to go till Mangalore.</p>

<p>Two weeks before the long weekend, <a href="https://twitter.com/nitishsp" target="_blank">Parkar</a> &amp; me discussed about this route and finalized the day-wise plan in just one sitting - a 6 days trip. Nothing else planned though. Parkar took around 5-7 warm-up rides across Bangalore during this time, and 2 days before the trip, we went for another 60 km+ warm-up ride to Hennur Forest. I was relieved after going for this warm-up ride because the sore muscles got recovered by the next day - just before the trip and, getting ready for a daily 80-100 km ride was important.</p>

<h3 id="section_1">Day 0: Finding the bus to Mangalore in heavy rains (with our bikes)</h3>
<p>
	<p>We did no prior bookings (buses and hotels) in advance since we were carrying bikes and things were not fully predictable. The weather forecast showed rains all along the route till next week. We packed all our gears, dry fruits, and other edibles, and left for the Majestic bus stand. It started raining heavily just after 2 km of start (around 8 PM). It seemed like the rain is not going to stop and we didn't want to negotiate with the last bus till Mangalore; so we wore our raincoat, <u>kept our mobile in our raincoat's pocket</u> and resumed. It was raining heavily. Risk apart, we always liked riding in the rains. At some places, half of the tires were submerged inside the logged water, but it was fun. This was the third time I was riding in such heavy rain and so much of water.</p>
	<p>It took us around 30-45 mins to find, convince, negotiate with a bus conductor to allow to keep our bikes in the luggage. These were <a href="">KSRTC Airavat</a> multi-axle semi-sleeper buses. We kept the bikes in vertical position supported with the bike stand inside the luggage compartment.</p>
	<p>Inside the bus, Parkar's phone was stuck in a boot loop, and we couldn't do anything to stop it. It kept restarting the whole night. My phone was working fine, but the moment I put it in charge, it probably short-circuited and the touch sensor stopped responding. Both our phones had stopped working. We learned that raincoat pockets are not waterproof.
	While the bus left by 11:30 PM, I was also constantly worried about cycle getting damaged on the way, esp while crossing the ghats.</p>
</p>

<h3 id="section_2">Day 1: Mangalore to Malpe Beach, Udupi, St. Mary's Island (62 km)</h3>
<p>
Getting good sleep in a semi-sleeper bus is tough, we took them because these buses have huge luggage compartments and they usually allow bikes. We got down at the Mangalore bus stand, put on our gears, and started the trip by 8 AM. This route was mostly highway - NH 66. We crossed many deltas, rivers as part of beautiful landscapes. At this point, I was slightly worried about our phones not working, but I wanted the experience to have completed this 6 days trip without phones or taking photos.</p>
<center><img style="border: 1px solid #ccc;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/mangalore_goa/malpe_udupi.jpg" alt="Malpe Udupi" /></center>
<p><br />Around 1 PM, we crossed Udupi quite easily and before leaving the highway for Udupi, we found a mobile shop and enquired if mobiles could be repaired. Parkar's phone got fixed by drying out the moisture from the phone, while I had to get my screen replaced (with another broken screen because we couldn't find a new screen in that area). Once my mobile was on, the first thing I did was tranferred the house rent to my house owner in Bangalore. We asked the shopkeeper for a good place to eat - for which he suggested a local shop that cooked good sea fishes. (people are generally very helpful on the highways)</p>

<p>We somehow found the place he suggested and had amazing (literally) fish curry. We gorged on 3-4 types of fishes which were all mostly deep-fried. Later, we took some internal roads to reach Malpe Beach, which was pretty clean and almost empty in the afternoon. We found that boat service for St. Mary's Island is closed due to bad weather which was disappointing. So, we found a lodge nearby and took some rest. In the evening, we spent some time on the beach, watched the sunset, clicked some pictures and saw huge fish markets nearby, before having dinner at one of the shops - fish curry meal again.</p>

<h3 id="section_3">Day 2: Murdeshwar (110 km)</h3>
<p>I wouldn't say I had a very good sleep (neither did Parkar), maybe because we were not tired enough, or it wasn't home. We got up at around 6 AM, packed up, and left for Murdeshwar. Again, the route didn't disappoint us, and we crossed some beautiful landscapes which involved beaches, deltas, and ghats. Like most days, we had Idli at some local shop on the way for the breakfast.</p>
<center><img style="border: 1px solid #ccc;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/mangalore_goa/murdeshwar.jpg" alt="Malpe Udupi" /></center>
<p>
<br />Before coming for this trip, the weather forecast showed it'll rain for the whole week through the whole west coast. But it didn't - so far. We were having early lunch at some restaurant (Masala Dosa &amp; coffee), and suddenly it started raining heavily. It was really bad and apparently, the people have been waiting for the rains for a couple of months. We decided we'll not wait for too long, and finally, wore the raincoat and started riding. Trust me on this, riding in the rains is indescribable - you've to experience this by yourself and especially when you're tired or on ghats.</p>
<p>We rode in the rains for little over one hour. We reached the beach late afternoon, searched for a place to stay and went out to eat (fish curry meal again, and some boiled eggs). Finding a good place to stay as well as to eat was not easy here since this place was slightly crowded because of the popular temple at the beach.</p>
<p>By 5 PM, we were at the beach for the daily sunset session.😁 We finally saw a lot of humans here, and dogs of course, since most places we went to were usually empty. At the beach, while I was feeling a bit tired for some reason, Parkar met (unusual Parkar) a large group of cyclists who were coming from Goa. They suggested a couple of internal routes that we can take, as well as some good places to stop by. I was just lying down at beach, while <b>Parkar talked</b> for more than an hour. By 9 PM, we left the beach and went for dinner. Every night, we would buy a liter of milk and have a protein shake before sleeping. We generally ate a lot of food to not lose a lot of weight and muscles.</p>

<h3 id="section_4">Day 3: Gokarna (80 km)</h3>
<p>Last night's sleep was not good again. For the most part of the night, I wasn't sure if I was sleeping or I was awake. It was weird. We got up early and left for Gokarna, we were comparatively more excited about reaching Gokarna. The route was a bit different now, more <i>hilly</i> to be specific since we were at the edge of ghats. Hilly route is a different experience - the reason is the ups and downs that we get. At one moment you're pedaling some big slopes, and suddenly there is a downward slope for some time.</p>
<center><img style="border: 1px solid #ccc;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/mangalore_goa/gokarna_1.jpg" alt="Malpe Udupi" /></center>
<p><br />Suggested by the cyclists yesterday, we decided to stop by a small footbridge over some river (Saraswati I guess) which looked good in the photos too. Since my phone was broken, Parkar was navigating the directions, but like a fool, I was cycling ahead of him. Probably because of some good song in the earphones, I was riding with very good speed and suddenly I got a call from Parkar, only to realize that I had come far ahead of the location where we had to stop. I went back and took around 20 minutes to find him (~5 km). It was a good place, and the bridge so narrow that it acted like a one-way. At the other side of the bridge, there was a broken road that seemed to go towards Gokarna, which we wanted to take, but we didn't risk our tires for it - especially tires of my road bike.</p>
<center><img style="border: 1px solid #ccc;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/mangalore_goa/gokarna_2.jpg" alt="Malpe Udupi" /></center>
<p><br />After a couple of hours, we decided to take an internal route and leave the highway (at Kumta). The good part was that this route went to Aghanashini Jetty which will directly drop us at "God's Own Beach" in Gokarna by a ferry. The bad part was that, for this odd 20 km, we had no idea about the condition of the roads. But we were excited and went for it.
<br />This was an amazing route. Roads were good, jungles, full of trees, and hilly terrain. As we were getting close to the shore, the slope of the road was suddenly increasing. It was a sudden change, and at a few places, we even had to walk upwards. I think the roads were at 60-70 degrees angle for some time. At the peak, we were able to clearly see nearby beaches, deltas, and Gokarna! Just like how we reached on the top, there was a sudden downward slope for the next 5kms on the narrow roads. There were no vehicles on this road. The downward slope directly landed us at the ferry station, which happened very quickly. It was around 1 pm and even in the bright sun, the landscape from the ferry was mesmerizing, clouds were clear, a mix of hot and cold breezes, and we had finally touched Gokarna (my first time). The surprising part was that we just had to pay 10 bucks for the ferry ride.
<br />Through the jungles and hilly routes in that part of Gokarna, we reached the Main beach by 3 pm. Unfortunately, everything was closed - shops, restaurants, etc and we were super hungry. We ate some peanuts and other snacks we had, found a place to stay, and took some rest. In the evening, we would spend the evening at the beach before finally having dinner at a small restaurant. Also, we parked our bikes inside the room on the third floor.😁
</p>

<h3 id="section_5">Day 4: Karwar, Polem, Palolem (90 km)</h3>
<p> I finally got a very good sleep the night before. Since the route from Gokarna till Palolem was very hilly, we didn't want to end up riding in the jungles in the dark. Our goal for today was to reach Karwar and stay there. Early morning, we had to catch a ferry at Gangavali Ferry Service by 7 am - that will not just save us 15 km, but will also take us through some good routes. We were now preferring these remote routes, after our last find. We reached there on time, the huge ferry was totally empty, and before departing it was full. People used that route daily as part of their commute. Apart from saving time for everybody, it only cost 10 bucks!
</p>
<p>After getting back to the highway, the last 30km before Karwar was very hilly, challenging and there were huge trucks passing by. These hilly routes took us through some big jungles and mountains. (edge of western ghats) By the time we reached the Karwar beach, it was only 12 pm, and even after the challenging route so far we were feeling good. So we decided that we'll continue and go till Palolem on the same day - because even in the worst case, we had 6 hours left. I clearly remember crossing the flat &amp; straight Karwar highway behind the Karwar beach at high speed and I stopped only after reaching a flyover with an amazing view. (photo below)
</p>
<center><img style="border: 1px solid #ccc;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/mangalore_goa/karwar_polem_1.jpg" alt="Malpe Udupi" /></center>
<p><br />After entering Goa, I wanted to stop at the Polem beach for some time which is my favorite beach. It's a remote beach and always empty. We went there but didn't waste too much time and moved ahead. The roads of South Goa are very good, have huge trees and it's hilly in most parts. Somewhere in the jungle, we spotted a restaurant. (there was nothing else in that area) We had our usual fish curry meal there, took some rest, and resumed the ride.
</p>
<center><img style="border: 1px solid #ccc;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/mangalore_goa/karwar_polem_2.jpg" alt="Malpe Udupi" /></center>
<p><br />At one point, we saw an under construction bridge, spotted a temporary footbridge to cross Glagibag river. We went off-road and walked on that bridge to reach the Glagibagh bridge. It was rare to spot humans around so far in the trip, but a couple gave us company while crossing that bridge - who were also going to the same beach. We also realized that we were well ahead of our worst-case time scenario and Palolem is not too far. This bridge actually was part of NH-66 that took us directly to Palolem. We reached there by 4 pm, took some rest and went to the beach for the sunset, but the weather was cloudy today. Meh. At first, we thought of spending another day in Palolem, but after some discussion, we decided we'll go to Panjim next day and stay for a day.
</p>

<h3 id="section_6">Day 5: Agonda, Cola, Panjim (80 km)</h3>
<p>Another good night's sleep, we were set to leave for Panjim. However, we decided to take a different route for it. Looking at the map, we saw two ways to reach Margaon. The first one was the familiar NH-66, and the other one was via Agonda and Cola - it's a state highway. At this point, we had no idea how amazing that route is going to be.</p>
<center><img style="border: 1px solid #ccc;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/mangalore_goa/goa.jpg" alt="Malpe Udupi" /></center>
<p><br />When we started riding, it was drizzling, but we kept moving. The route between Palolem and Agonda is familiar (since I had a barefoot run on this road, a year back). We were riding pretty fast, because of the amazing weather. This route was hands down <b>the best</b> in this whole trip. Jungles, hills, and once in a while spotting entire beaches range from the top (Agonda, Palolem etc beaches in one view). Cola was specifically amazing, this place is on ghats and within the jungle. There was nobody there (apart from a few random houses in the center of nowhere) and we could hear sounds of birds and some animals. Sometimes, it was scary as well, because we couldn't ride fast enough (or in fact we had to just walk sometimes because of the large upward slope) I was thinking, if one of those baboons attacked me, I won't even be able to run away.😂 It's hard to describe this route - drizzle, ghats, dense jungles, grass plains, birds and animals. We also spotted a French couple who were coming to Palolem from North Goa on cycle. We talked to them for a while, who were going to Kerala on a cycle over a month period.</p>

<p>We reached Margaon and after this, the roads were crowded with vehicles and people. By 1 pm, we had reached Panjim, and instead of looking for a room, we came to the bus stand and started searching for a bus to Bangalore. But there were no buses available - online or offline. After more than an hour of struggle and convincing about our cycles, a bus driver helped us and offered us two seats on the bus for extra money (extra money for cycles as well as for the seats). We got to know that every government bus has a couple of seats reserved for VIPs and usually it's filled at last moment. We got lucky.</p>

<p>The bus took the same route we came from. Within 2 hours we had already reached Karwar. From the window, we saw all the same places, restaurants and marks we had visited, and now we were passing by them in just a flash.</p>

<h3>Afterthoughts</h3>
<p>When we go for a long one-day trip, it requires a different mindset and preparation. Because you know that at the end you'll reach home and can rest as much as you want. But a long trip over multiple days requires a different kind of mindset. In this, you need to prepare for the next day's ride again - day after day. Both of them are an unique experience in themselves.</p>

<h3>Additional information</h3>
<p><b>Food &amp; Nutrition</b>
<br />Breakfast: generally Idli, Dosa from local shops
<br />Lunch: Fish curry meals and sometimes Dosa
<br />Dinner: Fish curry-rice, eggs/chicken and milk + protein shake before sleeping.
<br />We bought a huge number of water bottles throughout the trip. We always keep packets of Tang and mix in the water bottles.
<br /><b>Stay</b>
<br />We try to find lodges/hotels or home-stays between Rs. 700-1200 per night. It’s very easy to find them at highways and remote areas, plus we don’t look for anything fancy either.
<br /><b>Beached Visited</b>
<br />Malpe Beach, Maravanthe Beach, Murdeshwar Beach, Kadle Beach, Nirvana Beach, God’s Own Beach, Gokarna Main Beach, Karwar Beach, Polem Beach, Galgibaga Beach, Talpona Beach, Palolem Beach.
<br /><b>Bikes</b>
<br />Parkar: Btwin Rockride MTB
<br />Shekhar: Btwin Triban 100
<br /><b>Gears</b>
<br />Get the list from <a href="https://shekharsingh.com/blog/2019/06/11/long-cycling-ride-checklist-endurace-ride.html" target="_blank">here</a>.
<br />
<br />Although right now we don’t have any set plans, we’ll be back on the roads soon!</p>
 ]]></content>
</entry>


  <entry>
  <title type="text">Cycling Trip - Bangalore to Kolar/Avani village - 240 km in 11 hours</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2019/08/15/cycling-trip-bangalore-to-kolar-avani-240-km-in-11-hours.html" />
  <id>https://shekharsingh.com//blog/2019/08/15/cycling-trip-bangalore-to-kolar-avani-240-km-in-11-hours</id>
  <published>2019-08-15T00:00:00Z</published>
  <updated>2019-08-15T00:00:00Z</updated>
  <content type="html"><![CDATA[ <p><b>Content:</b></p>
<ul>
	<li><a href="#section_1">Why this trip?</a></li>
	<li><a href="#section_2">Places &amp; temples I visited</a></li>
	<li><a href="#section_3">Hardest part: The return trip to the home</a></li>
</ul>

<p><span style="color: #ccd;"><i>Note: This post is slightly detailed. I wanted to keep it as a “Notes to self”; because I don’t want to forget some of the moments from this trip; especially the 3rd part of this post.</i></span></p>

<p id="section_1">
  It's been a couple of months, that I had gone for a long cycling trip. 15th August on a Thursday means long weekend was coming (kind of). On Wednesday, I was thinking about the places I can go; but I and my cycling partner <a href="https://twitter.com/nitishsp" target="_blank">Nitish</a> (we call him <i>Parkar</i>) had been to most Bangalore's good places in the range of around ~120 km round trip. Kolar's blue water lake (also called "Dodda" or "Chhota Ladakh") was in my mind from last few times which is roughly 52 km from Indiranagar. In the Bangalore-Sakleshpura-Chikmangaluru cycling trip (a post soon), Parkar and I had clocked our best of 135 km in a single day. I wanted to go farther than that from quite some time, but couldn't find a good destination within the range. More than that, a destination which could be safe to go; if I get tired and could crash somewhere midway.
</p>

<p>
  Therefore, I decided to visit Kolar and cover some of the nearby ancient temples that I had heard of. I created a map which included the lake and 6 temples (Targetting ~220 km). Parkar couldn't join me as he was still recovering from the viral fever. In the evening, I washed the bike, did the basic checks and packed up the small decathlon bag with all the utilities (checklist <a href="http://localhost:3000/blog/2019/06/11/long-cycling-ride-checklist-endurace-ride.html" target="_blank">here</a>). I quickly prepared my go-to mixture of roasted grams + raisins + almonds + peanuts (~500gm overall). I knew that nutrition and hydration are going to be the deciding factor. I slept at around 1 AM since Me/Parkar/Vishwas were chilling at my home; which already delayed my plan by an hour. I got up at 6 AM.
</p>

<p>
  In the morning, I had to visit Parkar's house first, to get bike's chain lube, since the bike was not serviced for a while. Then, I checked the map, plugged-in earphones, started a long playlist and set the goal to come back home by 7 PM; a total of 12.5 hours trip.
  I started cycling at good speed; so that while returning I could spare a few hours in case things go bad. I bought a small Indian flag 🇮🇳 on the way (NH 75) since many people were selling it on the way throughout for Independence Day celebration. At this point, I realized I had forgotten to tie Rakhi :-( It was Rakshabandhan too.
</p>

<center><img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/dodda_blue_water_lake.jpg" alt="Kolar dodda blue water lake" style="width:600px;height:450px;" /></center>

<h3 id="section_2">Dodda ayur Chhota Ladakh</h3>
<p>
  In less than 2 hours, I had reached the Chhota Ladakh area. It was really fun so far, good songs and speed! My water bottle fell and broke due to a sudden speed breaker that I didn't see on the way. On the other hand, I couldn't find the lake for next ~30 minutes; since it was not correctly marked on the map, and no signs, etc. I moved in the wrong direction for about 2-3 km as well and then had to come back. Finally, reached the place after asking the only farmer I could see in that small village. The lake and rocks around were unexpectedly huge. The place was all empty, apart from a security guard (claimed by him); the strong winds made it a pretty chilling place.
</p>

<p><b>Kolar &amp; Avani</b> has a very rich history. Valmiki lived here, Lav &amp; Kush were born in Avani too. There are a large number of temples in this whole region. It’s very popular for Gold fields. <a href="https://en.wikipedia.org/wiki/Kolar" target="_blank">(wiki)</a></p>

<h3>Antharagange</h3>

<p>I had my breakfast bars, some dry fruits and I left for Kolar city, which was around 11 km from here. This was my fastest 11 km; which I completed in 17 mins; but again the location was marked incorrectly on Google Maps. I had to ride a few extra kms here and there to finally find it. This place is full of monkeys (actual monkeys, I mean) and it has trek starting through a bunch of staircases to many caves through the rocks. It’s a Lord Shiva’s temple, which means “The Ganges from the deep” in Kannada. It’s also known as Kashi of South. <a href="https://en.wikipedia.org/wiki/Antara_Gange" target="_blank">(wiki)</a> I had two tender coconuts before I left from here.</p>

<center><img style="width:650px;height:600px;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/antharagange.jpg" alt="Antara Gange" /></center>

<h3>Someshwara &amp; Kolaramma Temples</h3>
<p>Next two temples were within the Kolar city. Most of these temples were built by <a href="https://en.wikipedia.org/wiki/Chola_dynasty" target="_blank">Cholas</a> time. I covered them quickly and wanted to grab a breakfast too. Google Maps was showing that Kolar had a big lake, but when I reached the location, it was just a dried out huge lake with plastics, and trees inside it. Imagine, this state of the lake was during the monsoon.</p>

<div style="width: 750px; height: 390px;">
	<div style="width: 510px; height: 390px;float: left;">
		<img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/sri_somehwara.jpg" alt="Someshwara Temple" style="width:510px;" />	
	</div>
	<div style="width: 235px; height: 390px;float: left; margin-top: 9px;">
		<img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/kolaramma.jpg" alt="Kotilingeshwara Temple" style="height: 365px;" />
	</div>
</div>

<p>Anyway, I realized in the search of lake and a good Dosa place, I had come out of the city on a state highway (SH 96) which took me out of the city and back to NH 75. Also, I got a call from home and got scolded for not tying the rakhi yet. I borrowed a few hours from them. <u>While cycling, you can talk to people for long.</u> :)</p>

<p>I decided to have the proper breakfast after reaching my next stop, Avani Village, which was roughly 30 km from here. Plus, I have already been snacking on the items I got with me. I had a few glasses of sugarcane juice and I started for the next stop. Although, it’s not too tough to find restaurants on highways, sometimes it can get tough in remote areas; especially on a cycle.</p>

<p>Around 25 km later, I took a right-turn into Avani village, leaving the highway - which goes to Tirupathi. I saw a board saying it was 151 km from there, and it got me thinking if I should rather go Tirupathi, but maybe next time :) This road was better, huge trees on both sides and not wide like highways. Plus, my speed has been really good so far. I reached the next temple within 1 hour 12 mins. These villages were really small. I didn’t see a lot of people. Weather was okay, not too humid or too hot.</p>

<h3>Ramalingeshwara Temples</h3>
<p>These temples were a group of many temples. They were built before Chola dynasty (10th century), who had renovated these. There were barely 5-7 people around though. I roamed around, read some of the stories on the boards, and then took a nap for 15 minutes on a huge stone under a tree. I decided to leave for the next place by 1 PM. I ate most of the <a href="https://en.wikipedia.org/wiki/Chikki" target="_blank">chikki</a> I had, drank water and left for the next place at 1 PM.</p>
<div style="width: 750px; height: 600px;">
	<div style="width: 750px; height: 285px;float: left;">
		<div style="width: 370px; height: 300px;float: left;margin-right: 5px;">
			<img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/ramalingeshwara_1.jpg" alt="Kotilingeshwara Temple" style="width:390px;" />	
		</div>
		<div style="width: 370px; height: 300px;float: left;">
			<img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/ramalingeshwara_2.jpg" alt="Kotilingeshwara Temple" style="width:390px;" />	
		</div>
	</div>
	<div style="width: 750px; height: 300px;float: left;">
		<div style="width: 370px; height: 300px;float: left;margin-right: 5px;">
			<img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/ramalingeshwara_3.jpg" alt="Kotilingeshwara Temple" style="width:390px;" />	
		</div>
		<div style="width: 370px; height: 300px;float: left;">
			<img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/ramalingeshwara_4.jpg" alt="Kotilingeshwara Temple" style="width:390px;height: 278px;" />	
		</div>
	</div>
</div>

<p>These were really bad roads. For a stretch of over 8-10 km, I went through those patchy and broken roads. I was slightly worried about the cycle, since it has only hybrid tyres, and it’s not a mountain bike. These roads took me to some very remote areas, small villages, jungles, and very dry lands. I was constantly checking maps since there were a lot of turns and I didn’t want to take some bad route. Finally, I reached the next destination in a village.</p>

<h3>Kotilingeshwara Temple</h3>
<p>Unlike, all the above temples, this temple was super crowded. Suddenly, I could see a lot of humans around. This temple is not a very old temple and is also called mini-Tirupathi. It has the largest Shivling in the world and has 10 million+ small-sized Shivlings. It looked like a huge shop at first, but these Shivlings are actually donated by the devotees.</p>
<center><img style="width:500px;" class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/kotilingeshwara.jpg" alt="Kotilingeshwara Temple" /></center>
<p>It was very crowded, and I set the time of 3 PM to start for my return trip. I had to skip the huge queue to go inside the main temple. Although they were offering free meals there, I decided to finally have my lunch outside in a local Dosa shop. Two Onion Dosas. Bought a water bottle and I left from here.
<br /></p>

<h3 id="section_3">Hardest part: The return trip to the Home</h3>
<p>I checked on the map; it was 90 km. I thought it shouldn’t take me more than 4.5 hours to reach home considering the trip so far. I’ve been feeling pretty good; except for the bad road part and was not fully tired yet.</p>

<p>After around next 4-5 km, I realized that I was riding at a slower speed for some reason, plus I started getting tired. Soon, I understood that I was going against the direction of winds, which was added trouble on those roads with so many up-and-downs. I was surprised to face such high impact of winds. My next goal was to cut into NH 75 near Kolar, which was around 32 km. This stretch was the toughest. I drank a lot of water, ate some more carbs, in that jungle-ish and dry land road. It was SH-96. I couldn’t ride well. But I thought, once I get back to the highway, I will be able to get the speed. So my goal was to just reach Kolar. By the way, I had not still tied the Rakhi. <u>I could read the notifications in my watch's screen that my family's Whatsapp group was angry at me.</u></p>

<p>It took me <b>2.5 hours</b> to finish this stretch. This drained out all my energy and suddenly I started to have lower back pain, knees + legs pain, and palms were getting numb. The pain was expected even before I started the trip. In all my previous trips, I  never had pain in my lower legs, but this time maybe because of higher speed, it caught me. I put the pain relief spray, which eventually helped with my lower back pain after 30 minutes. But the legs were in bad shape.</p>

<p>After reaching Kolar on NH 75, I had 60 km to go. Unexpectedly, within 10 km, I felt I was riding really slow. The opposing wind was still there. I was worried that I might have to ride till very late in the night on this highway, which is not safe considering there are no street lights on most part of the highways. I wanted to reach the next major stop, Hoskote. which was 40 km from Kolar. I thought I was riding at a speed of 12-13 km/hour, which was really bad. Highways are un-even, there are too many ups-and-downs, flyovers, etc; which you realize only if you’re running or cycling. <b><i>I had given up at this point.</i></b> So I planned to take a lift till Hoskote from some truck or lorry. In my first attempt, one lorry stopped, but he said, he is going to take the next immediate left, which he actually took in 50 meters. That was slightly disappointing. I checked the maps for the distance and I realized, I was averaging exactly 20 kmph. This was good news, suddenly my calculations were on the safer side, and I felt slightly motivated. My phone battery was now 20%, so <u>I had to turn off the music at this point</u>. Only Google Maps was active now.</p>

<p><b>In my head, I made a plan</b> that I’ll take a 5 minutes break, in every 30 minutes, and after every 10 km. Which means I will reach Bangalore by 7:30 PM and home before 9 PM. I broke that remaining 50 km into 5 chunks. Hoskote was 30 km from there.</p>

<p>My palms were aching and slightly numb. Legs were painful. But my plan was working. I was clocking exact 20 kmph. Meanwhile, It was getting dark, I kept dropping my location as checkpoints to Parkar/Vishwas in a Whatsapp group; and actually, asked them, <i>If I don’t call them by 9 PM, give me a call.</i> On the highway, I could see every kilometer getting reduced to Hoskote on those sideboards.</p>

<p><b>At this point, I had only the following things going in my head</b>: 1. Tie Rakhi when you reach home. 2. Cover next 10 km in 30 minutes. 3. Reach Hoskote. 4. Eminem’s <i>Till I Collapse</i> verse. I couldn’t literally think of anything else happening in my life, I couldn’t sing any songs in my head either. Usually, I love the time when I ain’t thinking about anything else. eg, during a workout, or some deep work. But this was different.</p>

<p>Soon, I could see more trucks and street lights, and therefore I knew Hoskote was close. I filled my pocket with all the remaining roasted grams + almonds etc mix I had and kept eating it. I had reached Bangalore’s outer area, with exactly as planned time. I was very happy at this point and my next goal was to reach home :) At this point, I couldn’t speak the whole Eminem’s verse in my head either: I could only say <i>Till I Collapse</i>, which sometimes I even shouted to keep myself active mentally.</p>

<p>But Bangalore’s traffic was as usual bad in the evening. I had to stop at many signals and a few traffic jams. Problem with stopping was that <i>it breaks the momentum and standing on the feet was more painful that pedaling the bicycle.</i> The last 10 km turned out to be much worse, because of traffic. I reached home at exact 8:30 PM.</p>

<p>I drank a few sips of water and crashed on the bed. I was feeling much weaker on the bed than on the cycle; maybe because I was home. I zoned out, and got up after 30 mins, I took shower, tied all 7 Rakhis and sent the photo to my family’s Whatsapp group. Two ORS, Eat Fit’s spinach soup and half-liter milk helped me feel much better after 2 hours.</p>

<p><br /></p>
<h4><i>
We can overcome any problem in life if we split the problem into small milestones/steps and just focus on one step at a time.
</i></h4>

<p><br />
Here’s the map of the trip:</p>

<center><img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/kolar_avani/map.png" alt="Map" style="width:750px;height:220px;" /></center>
<!-- https://www.google.co.in/maps/dir/Indiranagar,+Bengaluru,+Karnataka/Dodda+ayur+Chhota+Ladakh,+Arabikothanur,+Karnataka+563133/Antharagange+Main+Road,+Kuvempu+Nagar,+Kolar,+Karnataka/Sri+Someshwara+Temple,+Fort+Area,+Kolar,+Karnataka/Kolaramma+Temple,+Fort+Area,+Kolar,+Karnataka/Ramalingeshwara+Temple,+Avani,+Karnataka/Shree+Kotilingeshwara+Swamy+Temple,+Road,+Ghattakamadenahalli,+Karnataka/Indiranagar,+Bengaluru,+Karnataka/@13.116783,77.9819646,11z/data=!4m50!4m49!1m5!1m1!1s0x3bae16a418770391:0xb50f46b826501036!2m2!1d77.6408356!2d12.9783692!1m5!1m1!1s0x3badfb7c8a1d3b19:0x89e9f0e21855fe44!2m2!1d78.0241684!2d13.1148468!1m5!1m1!1s0x3badf09d2efe6ebf:0xfb33139875963da!2m2!1d78.115183!2d13.1377839!1m5!1m1!1s0x3badff7368206e87:0xd564cfd017b0d933!2m2!1d78.13823!2d13.1374815!1m5!1m1!1s0x3badf0f22254065f:0xa579ad6d50b3e353!2m2!1d78.1391205!2d13.1384881!1m5!1m1!1s0x3bad8db3dd415165:0x805925a2adc42e9!2m2!1d78.3294587!2d13.1070527!1m5!1m1!1s0x3bad94ab7b67cf47:0x1528ee14bcc9a5be!2m2!1d78.2957015!2d12.9951555!1m5!1m1!1s0x3bae16a418770391:0xb50f46b826501036!2m2!1d77.6408356!2d12.9783692!3e0 -->
 ]]></content>
</entry>


  <entry>
  <title type="text">Checklist - Long cycling ride (endurance rides)</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2019/06/11/long-cycling-ride-checklist-endurace-ride.html" />
  <id>https://shekharsingh.com//blog/2019/06/11/long-cycling-ride-checklist-endurace-ride</id>
  <published>2019-06-11T00:00:00Z</published>
  <updated>2019-06-11T00:00:00Z</updated>
  <content type="html"><![CDATA[ <p>
Every time I plan for a cycling trip, while preparing I always think about if I'm missing anything. This post is to fix that. I'll add a similar checklist for running and hiking as well.
</p>

<center><img class="img-responsive" src="https://shekharsingh.com//assets/images/cycling_trip/cycling_checklist.jpg" alt="Kolar dodda blue water lake" style="width:750px;height:400px;" /></center>

<h4>Checklist:</h4>

<p><b>For Cycle:</b><br />
<input type="checkbox" /> Cycling Helmet (<a target="_blank" href="https://www.decathlon.in/p/8500051_st-50-mountain-bike-helmet-black.html">decathlon</a>)<br />
<input type="checkbox" /> Wrench Spanner (<a target="_blank" href="https://www.amazon.in/dp/B00LGE1Z">amazon</a>)<br />
<input type="checkbox" /> 2 Cycle tyre tubes (<a target="_blank" href="https://www.decathlon.in/p/8311095_700x1825-inner-tube-80mm-presta.html">decathlon</a>)<br />
<input type="checkbox" /> Tyre levers (<a target="_blank" href="https://www.decathlon.in/p/8359629_puncture-repair-kit-and-adjustments-500-hand-pump-3-tyre-levers-1-multitool.html">decathlon</a>)<br />
<input type="checkbox" /> Multitool (<a target="_blank" href="https://www.decathlon.in/p/8359629_puncture-repair-kit-and-adjustments-500-hand-pump-3-tyre-levers-1-multitool.html">decathlon</a>)<br />
<input type="checkbox" /> Cycle Hand Pump (<a target="_blank" href="https://www.decathlon.in/p/8359629_puncture-repair-kit-and-adjustments-500-hand-pump-3-tyre-levers-1-multitool.html">decathlon</a>)<br /></p>

<p><b>For you:</b><br />
<input type="checkbox" /> Cycling gloves (<a target="_blank" href="https://www.decathlon.in/p/8327103_300-cycling-gloves-black.html">decathlon</a>)<br />
<input type="checkbox" /> Cycle foam saddle (<a target="_blank" href="https://www.decathlon.in/p/8381098_500-memory-foam-saddle-cover-size-m-black.html">decathlon</a>)<br />
<input type="checkbox" /> Cycling sunglasses (<a target="_blank" href="https://www.decathlon.in/p/8118519_arenberg-sunglasses-cycling-running-adult-yellow-category-1.html">decathlon</a>)<br />
<input type="checkbox" /> Arm UV protection cover (<a target="_blank" href="https://www.decathlon.in/p/8518751_roadr-arm-cover-uv-black.html">decathlon</a>)<br />
<input type="checkbox" /> Face mask/Headband (<a target="_blank" href="https://www.decathlon.in/p/8493103_mountain-trekking-headband-trek-500-multi-position-black.html">decathlon</a>)<br />
<input type="checkbox" /> Raincoat (<a target="_blank" href="https://www.decathlon.in/p/8300326_rain-cut-men-s-rain-hiking-jacket-black.html">decathlon</a>)<br />
<input type="checkbox" /> Earphones <br /></p>

<p><b>Others:</b><br />
<input type="checkbox" /> A small bag (waterproof if possible) (<a target="_blank" href="https://www.decathlon.in/p/8348925_arpenaz-10-ultra-compact-ultra-lightweight-backpack-blue.html">decathlon</a>)<br />
<input type="checkbox" /> Small Plastic to cover bag or carry cash<br />
<input type="checkbox" /> Some cash<br />
<input type="checkbox" /> ID proof<br />
<input type="checkbox" /> Emergency contact details<br />
<input type="checkbox" /> Power bank<br />
<input type="checkbox" /> Pain relief spray<br />
<input type="checkbox" /> Tourch<br /></p>

<p><b>Nutrition:</b><br />
<input type="checkbox" /> Breakfast bars (Yoga bars etc)<br />
<input type="checkbox" /> My favourite: Roasted Grams + Almonds + Peanuts + Raisins mix<br />
<input type="checkbox" /> Chikki and other dry fruits<br />
<input type="checkbox" /> Water bottle(s)<br />
<input type="checkbox" /> ORS / Tang etc.<br /></p>

<p><br />
Note: Make sure to get the items as per your cycle’s size. These links are mostly where I got them from.</p>

<p>Add a comment if you think I’m missing anything.</p>

 ]]></content>
</entry>


  <entry>
  <title type="text">Analyzing Python Pandas' memory leak and the fix</title>
  <link rel="alternate" type="text/html" href="https://shekharsingh.com///blog/2019/03/26/analyzing-pandas-memory-leak-issue-with-fix.html" />
  <id>https://shekharsingh.com//blog/2019/03/26/analyzing-pandas-memory-leak-issue-with-fix</id>
  <published>2019-03-26T00:00:00Z</published>
  <updated>2019-03-26T00:00:00Z</updated>
  <content type="html"><![CDATA[ <p>At <a target="_blank" href="https://getsimpl.com">Simpl</a>, we use <a target="_blank" href="https://pandas.pydata.org/">pandas</a> heavily to run a bunch of our machine learning models many of them implemented with scikit-learn. We’ve been growing rapidly and sometime back, one of the models crashed with python’s <code class="language-plaintext highlighter-rouge">MemoryError</code> exception. We were pretty sure that the hardware resources are enough to run the task.</p>

<p>What is the <b>MemoryError</b>? It’s an exception thrown by interpreter when not enough memory is available for creation of new python objects or for a running operation.</p>

<p>The catch here is that, it doesn’t necessarily mean “not enough memory available”. It could also mean that, there are some objects that are still not cleaned up by Garbage Cleaner (GC).</p>

<p>To test this, I wrote a very small script:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">arr</span> <span class="o">=</span> <span class="n">numpy</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">10000000</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">blast</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10000</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">pandas</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">arr</span><span class="p">.</span><span class="n">copy</span><span class="p">())</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">x</span><span class="p">.</span><span class="n">xs</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span>

<span class="n">blast</span><span class="p">()</span>
</code></pre></div></div>

<p>Below is the distribution (Memory usage w.r.t Time) <u>before the program crashed</u> with MemoryError exception.</p>

<p><img class="img-responsive" src="https://shekharsingh.com//assets/images/pandas_memory_leak.png" alt="Pandas memory leak" /></p>

<p>The GC seems to be working fine, but it’s not able to clean up the objects as fast as it’s required in this case.
<br /><br /></p>

<p><b>What’s the issue?</b><br />
Python’s default implementation is <code class="language-plaintext highlighter-rouge">CPython</code> (<a target="_blank" href="https://github.com/python/cpython">github</a>) which is implemented in C. The problem was <a target="_blank" href="https://sourceware.org/bugzilla/show_bug.cgi?id=14827">this</a> bug; in the implementation of <code class="language-plaintext highlighter-rouge">malloc</code> in <code class="language-plaintext highlighter-rouge">glibc</code> (which is GNU’s implementation of C standard library).
<br /><br /></p>

<p><b>Issue Details</b>:<br />
<code class="language-plaintext highlighter-rouge">M_MXFAST</code> is the maximum size of a requested block that is served by using optimized memory containers called <code class="language-plaintext highlighter-rouge">fastbins</code>. <code class="language-plaintext highlighter-rouge">free()</code> is called when a memory cleanup of allocated space is required; which triggers the trimming of fastbins. Apparently, when <code class="language-plaintext highlighter-rouge">malloc()</code> is less than <code class="language-plaintext highlighter-rouge">M_MXFAST</code>, <code class="language-plaintext highlighter-rouge">free()</code> is not trimming fastbins. But, if we manually call <code class="language-plaintext highlighter-rouge">malloc_trim(0)</code> at that point, it should free() up those fastbins as well.</p>

<p>Here is a snippet from <code class="language-plaintext highlighter-rouge">malloc.c</code>’s <code class="language-plaintext highlighter-rouge">free()</code> implementation (alias <code class="language-plaintext highlighter-rouge">__libc_free</code>). (<a target="_blank" href="https://code.woboq.org/userspace/glibc/malloc/malloc.c.html#3115">link</a>)</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">p</span> <span class="o">=</span> <span class="n">mem2chunk</span> <span class="p">(</span><span class="n">mem</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">chunk_is_mmapped</span> <span class="p">(</span><span class="n">p</span><span class="p">))</span>                       <span class="cm">/* release mmapped memory. */</span>
    <span class="p">{</span>
      <span class="cm">/* See if the dynamic brk/mmap threshold needs adjusting.
         Dumped fake mmapped chunks do not affect the threshold.  */</span>
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">mp_</span><span class="p">.</span><span class="n">no_dyn_threshold</span>
          <span class="o">&amp;&amp;</span> <span class="n">chunksize_nomask</span> <span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">mp_</span><span class="p">.</span><span class="n">mmap_threshold</span>
          <span class="o">&amp;&amp;</span> <span class="n">chunksize_nomask</span> <span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="n">DEFAULT_MMAP_THRESHOLD_MAX</span>
          <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">DUMPED_MAIN_ARENA_CHUNK</span> <span class="p">(</span><span class="n">p</span><span class="p">))</span>
        <span class="p">{</span>
          <span class="n">mp_</span><span class="p">.</span><span class="n">mmap_threshold</span> <span class="o">=</span> <span class="n">chunksize</span> <span class="p">(</span><span class="n">p</span><span class="p">);</span>
          <span class="n">mp_</span><span class="p">.</span><span class="n">trim_threshold</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">mp_</span><span class="p">.</span><span class="n">mmap_threshold</span><span class="p">;</span>
          <span class="n">LIBC_PROBE</span> <span class="p">(</span><span class="n">memory_mallopt_free_dyn_thresholds</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span>
                      <span class="n">mp_</span><span class="p">.</span><span class="n">mmap_threshold</span><span class="p">,</span> <span class="n">mp_</span><span class="p">.</span><span class="n">trim_threshold</span><span class="p">);</span>
        <span class="p">}</span>
      <span class="n">munmap_chunk</span> <span class="p">(</span><span class="n">p</span><span class="p">);</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
</code></pre></div></div>

<p>Therefore, we need to trigger <code class="language-plaintext highlighter-rouge">malloc_trim(0)</code> from our python code written above; which we can easily do using <code class="language-plaintext highlighter-rouge">ctypes</code> module.
<br /><br />
The fixed implementation looks like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">ctypes</span> <span class="kn">import</span> <span class="n">cdll</span><span class="p">,</span> <span class="n">CDLL</span>
<span class="n">cdll</span><span class="p">.</span><span class="n">LoadLibrary</span><span class="p">(</span><span class="s">"libc.so.6"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">CDLL</span><span class="p">(</span><span class="s">"libc.so.6"</span><span class="p">)</span>
<span class="n">libc</span><span class="p">.</span><span class="n">malloc_trim</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>

<span class="n">arr</span> <span class="o">=</span> <span class="n">numpy</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">10000000</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">blast</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10000</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">pandas</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">arr</span><span class="p">.</span><span class="n">copy</span><span class="p">())</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">x</span><span class="p">.</span><span class="n">xs</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span>
        <span class="n">libc</span><span class="p">.</span><span class="n">malloc_trim</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>

<span class="n">blast</span><span class="p">()</span>
</code></pre></div></div>
<p><br />
In another solution, I tried forcing the GC using python’s <code class="language-plaintext highlighter-rouge">gc</code> module; which gave the results similar to above method.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">gc</span>

<span class="n">arr</span> <span class="o">=</span> <span class="n">numpy</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">10000000</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">blast</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10000</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">pandas</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">arr</span><span class="p">.</span><span class="n">copy</span><span class="p">())</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">x</span><span class="p">.</span><span class="n">xs</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span>
        <span class="n">gc</span><span class="p">.</span><span class="n">collect</span><span class="p">()</span> <span class="c1"># Forced GC
</span>
<span class="n">blast</span><span class="p">()</span>
</code></pre></div></div>
<p><br />
The distrubution of Memory usage w.r.t Time looked much better now, and there was almost no difference in execution time. (see the “dark blue” line)</p>
<p><img class="img-responsive" src="https://shekharsingh.com//assets/images/pandas_memory_leak_fix.png" alt="Pandas memory leak with fix" /></p>

<p><br /><br />
Similar cases, References and other notes:</p>
<ol>
  <li>Even after doing <code class="language-plaintext highlighter-rouge">low_memory=False</code> while reading a CSV using <code class="language-plaintext highlighter-rouge">pandas.read_csv</code>, it crashes with <code class="language-plaintext highlighter-rouge">MemoryError</code> exception, even though the CSV is not bigger than the RAM.</li>
  <li>Explanation of malloc(), calloc(), free(), realloc() deserves a separate post altogether. I’ll post that soon.</li>
  <li>Similar reported issues:<br />
     - https://github.com/pandas-dev/pandas/issues/2659<br />
     - https://github.com/pandas-dev/pandas/issues/21353<br /></li>
</ol>

 ]]></content>
</entry>



</feed>
