<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://tbaraniecki.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tbaraniecki.com/" rel="alternate" type="text/html" /><updated>2025-02-23T15:51:39+00:00</updated><id>https://tbaraniecki.com/feed.xml</id><title type="html">Tomasz Baraniecki</title><subtitle></subtitle><entry><title type="html">Emotional intelligence at a workplace</title><link href="https://tbaraniecki.com/emotional-intelligence-at-workplace.html" rel="alternate" type="text/html" title="Emotional intelligence at a workplace" /><published>2025-02-07T00:00:00+00:00</published><updated>2025-02-07T00:00:00+00:00</updated><id>https://tbaraniecki.com/emotional-intelligence-at-workplace</id><content type="html" xml:base="https://tbaraniecki.com/emotional-intelligence-at-workplace.html"><![CDATA[<h2 id="what-it-is"><strong>What it is?</strong></h2>

<p>Emotional intelligence is composed of a few pieces. At its core is the ability to understand how I actually feel. Another piece is the ability to observe myself. Yet another piece is perspective—wondering if this feeling is temporary or long-term. There is also self-reflection. A crucial piece is recognizing that this experience happens to many people—that the feeling is totally normal. It involves observing myself in that moment and conceptualizing my mental state.</p>

<p>It allows me to detach a little bit and be an observer of myself. At first, it takes a lot of energy to understand myself, but it is like going to the gym—the more I do it, the less energy it requires.</p>

<p>So, now that I know how I feel, I understand my situation, my perspective, and what led me to this place. And here comes the part where I know myself. Let’s be honest: people, at their core, are not so different. We all have feelings, needs, urges, and an ego that needs boosting. Not everyone is aware of all these aspects.</p>

<p>Once I understood myself, I could understand the people around me by inferring what they did or did not say and considering their situation. By observing all of those details, I could get a glimpse of how they feel.</p>

<p>Okay, now that we have reached the point where I can understand another person, I can offer support by sharing another perspective or, depending on the situation, providing a reality check.</p>

<p>To sum up, emotional intelligence is the ability to put myself in someone else’s shoes, offer support and guidance if necessary, share another perspective, and suggest solutions.</p>

<hr />

<h2 id="how-it-affects-the-workplace"><strong>How it affects the workplace</strong></h2>

<p>Having close connections is necessary for mental well-being. As I have seen and experienced myself, once you are not understood, your energy and motivation slowly fade away. You have to feel mentally well in order to do good work. For me, nothing makes me feel better than the feeling of being surrounded by people who understand me.</p>

<p>Emotional intelligence helps with communication. Seriously, as I have seen, most conflicts or misunderstandings arise from a lack of simple communication.</p>

<hr />

<h2 id="basic-examples"><strong>Basic examples</strong></h2>

<ul>
  <li><strong>Example 1:</strong><br />
Developers are pairing: one wants to end work for the day because he is tired, while the other is result-driven. The result-driven developer has more energy and, in conclusion, overpowers the other’s need.
    <ul>
      <li><strong>What happened here?</strong><br />
They delivered on the same day, even though the first developer was depleted. The second one did not take the first’s needs into consideration.</li>
      <li><strong>What were the consequences in the long run?</strong><br />
Consider that this did not happen just once—it was a pattern. The first developer ended up with lower motivation (energy, dopamine, you name it).</li>
    </ul>
  </li>
  <li><strong>Example 2:</strong><br />
A fresh teammate pairs with a developer who knows the project well.
    <ul>
      <li>For me, it is crucial for an experienced developer to allow a fresh team member to do some tasks—even if it takes longer at the beginning—in order to gain confidence, experience, and the energy that comes from wins. Working on a task with someone else is like sharing a meal: you get better portions, you gain energy, you share, and you both benefit. Later on, once the developer who knows the project is fulfilled in his role, he can find fulfillment in supporting others on their journey and celebrating their accomplishments.</li>
    </ul>
  </li>
</ul>

<hr />

<h2 id="conclusion"><strong>Conclusion</strong></h2>

<p>In my opinion, emotional intelligence—at some level—is necessary to be part of a team, to drive higher velocity, and to create an environment in which people have the energy and mental drive to work. In the end, I want to work for a manager who understands me.</p>]]></content><author><name></name></author><category term="psychology" /><category term="people-lead" /><summary type="html"><![CDATA[What it is?]]></summary></entry><entry><title type="html">ElasticSearch Query Slowdowns</title><link href="https://tbaraniecki.com/elasticsearch-query-slowdowns.html" rel="alternate" type="text/html" title="ElasticSearch Query Slowdowns" /><published>2025-02-05T00:00:00+00:00</published><updated>2025-02-05T00:00:00+00:00</updated><id>https://tbaraniecki.com/elasticsearch-query-slowdowns</id><content type="html" xml:base="https://tbaraniecki.com/elasticsearch-query-slowdowns.html"><![CDATA[<p>Our Elasticsearch (ES) cluster was experiencing unpredictable query slowdowns due to irregular upsert volumes. The slowdown occurred mostly during increased write times. We seen it on Graph. We knew what workers were running at those times. Grafana was used for monitoring.</p>

<h2 id="project-overview"><strong>Project Overview</strong></h2>

<p>The project was an aggregator of merchant products, synchronized from XML feeds. The key details:</p>

<ul>
  <li><strong>Products table:</strong> 10M+ records, with 1-2M active at a time.</li>
  <li><strong>Database:</strong> MariaDB was the source of truth.</li>
  <li><strong>Elasticsearch Role:</strong> Used for sorting and querying product data, while details were fetched from the database based on product IDs.</li>
  <li><strong>Product States:</strong> <code class="language-plaintext highlighter-rouge">active | inactive</code></li>
  <li><strong>Merchant States:</strong> <code class="language-plaintext highlighter-rouge">paid | free | disabled</code> (plus a fourth state, which I don’t recall).</li>
  <li><strong>Elasticsearch Indexing:</strong> Only <code class="language-plaintext highlighter-rouge">active</code> products from <code class="language-plaintext highlighter-rouge">paid</code> or <code class="language-plaintext highlighter-rouge">free</code> merchants were indexed.</li>
  <li><strong>Frequent Changes:</strong> Products were continuously inserted, updated, or deleted in ES based on product and merchant state, workers processing specified product attributes and changes made by marketing moderators.</li>
</ul>

<h3 id="workflow-with-multiple-workers"><strong>Workflow with Multiple Workers</strong></h3>

<p>We had multiple workers handling different attributes of records, some workers had ability to create all attributes of a record.</p>

<ul>
  <li><strong>SynchronizerWorker</strong>
    <ul>
      <li><strong>{ ‘1’ =&gt; { ‘product_id’ =&gt; 1, title: ‘’, vectors: [], price: 300.2, category_id: 10 } }</strong></li>
    </ul>
  </li>
  <li><strong>VectorsWorker</strong>
    <ul>
      <li><strong>{ ‘1’ =&gt; { ‘product_id’ =&gt; 1, vectors: { a: [], b: [], c: []} } }</strong></li>
    </ul>
  </li>
  <li><strong>TitleWorker</strong>
    <ul>
      <li><strong>{ ‘1’ =&gt; { ‘product_id’ =&gt; 1, title: ‘’ } }</strong></li>
    </ul>
  </li>
  <li><strong>DescriptionWorker</strong>
    <ul>
      <li><strong>{ ‘1’ =&gt; { ‘product_id’ =&gt; 1, description: ‘lorem ipsum’ } }</strong></li>
    </ul>
  </li>
  <li><strong>DeletionWorker</strong></li>
  <li><strong>AdminWorker</strong>
    <ul>
      <li><strong>{ ‘1’ =&gt; { ‘product_id’ =&gt; 1, category_id: 2 } }</strong></li>
    </ul>
  </li>
</ul>

<p>Most ot these could trigger <code class="language-plaintext highlighter-rouge">ProductUpsertWorker, ProductDeleteWorker</code>, leading to ES updates. Since these updates were not synchronized, they caused congestion, affecting query performance. Several processes handled ES queue jobs, but unpredictable workloads created bottlenecks. ES works with updates like this, that it creates a new version of updated record, and than forward new version to other nodes in cluster. In Grafana we were seeing spikes in memory usage. During that times ES used more ram memory to handle inserts/upserts than for query performance - there is more to write about how ES handle creation/updates of records.</p>

<h2 id="potential-solutions-considered"><strong>Potential Solutions Considered</strong></h2>

<ol>
  <li><strong>Hardcode worker execution times</strong>
    <ol>
      <li>pros: for a time beeing it might help</li>
      <li>cons:
        <ol>
          <li>hard to maintain over long period of time</li>
          <li>every time we will add new worker or process it might have cascading effect</li>
        </ol>
      </li>
    </ol>
  </li>
  <li><strong>Upgrade Elasticsearch hardware - faster NVMe hard drives</strong> (not an option due to non-budget constraints).</li>
  <li><strong>Implement a single pipeline for ES updates</strong> (chosen approach).
    <ol>
      <li>knows what happens</li>
      <li>easy to debug - one point of failure</li>
      <li>one master over cluster</li>
      <li>possibility to increase workload</li>
      <li>scalable</li>
      <li>testable solution</li>
    </ol>
  </li>
  <li><strong>Increment cache TTL on catalogue aggregation query</strong> (also implemented)
    <ol>
      <li>first touch was to increase cache time, considered outdated data in ES</li>
    </ol>
  </li>
</ol>

<h2 id="constraints"><strong>Constraints</strong></h2>

<ul>
  <li>No additional hardware investment.</li>
  <li>Limited developer time.</li>
  <li>Minimal reliance on an external DevOps team (we were not their priority in case of new features)</li>
  <li>Maintainability</li>
</ul>

<h2 id="chosen-solution-onepipeline"><strong>Chosen Solution: OnePipeline</strong></h2>

<h3 id="goals"><strong>Goals</strong></h3>

<ol>
  <li>Centralize upserts/deletions to ES.</li>
  <li>Batch and merge product updates before writing to ES.</li>
  <li>Ensure fail-safety and retry mechanisms.</li>
  <li>Reduce the number of upserts per product.</li>
  <li>Implement a throttling mechanism.</li>
  <li>Allow disabling ES writes completely (done by turning cron job on and off)</li>
  <li>Enable a gradual transition to OnePipeline from the old system.</li>
</ol>

<h3 id="centralize-upsertsdeletions-in-one-place"><strong>Centralize upserts/deletions in one place.</strong></h3>

<p>Workers were scattered over few applications. We need a central job to gather all data. And also to stream data. Because it was used, we knew it well enough, metrics were in place, integrations also, obvious choice was Kafka. We had an internal gem for message production, making it simple to send messages:</p>

<p>Messages::Produce.perform_async(“one-pipeline”, message_hash)</p>

<p>However, handling message data was tricky due to JSON parsing variations (e.g., symbolized vs. string keys, newline handling when pushing message from line file).</p>

<h3 id="implementation"><strong>Implementation</strong></h3>

<ol>
  <li><strong>Kafka Consumer with Karafka</strong>
    <ul>
      <li>Used Karafka to fetch multiple messages from a Kafka topic into an array.</li>
      <li>Each message was a hash with one oraz many <code class="language-plaintext highlighter-rouge">product_id</code> as the keys.
        <ul>
          <li>{ ‘1’ =&gt; { ‘title’ =&gt; ‘Awesome Red Product’ } }</li>
        </ul>
      </li>
      <li>Later on, in next iterations, messages were grouped under <code class="language-plaintext highlighter-rouge">upsert</code> or <code class="language-plaintext highlighter-rouge">delete</code>, also supporting ES 5 and ES 7 formats - hash structure for both versions were slightly different)</li>
      <li>Deep merging enabled us not to do multiple updates for the same product.</li>
    </ul>
  </li>
  <li><strong>Handling Kafka Limitations</strong>
    <ul>
      <li>Karafka was limited to fetching 1000 messages per batch, which was insufficient.</li>
      <li>Alternative Kafka clients required additional dependencies and infrastructure changes (PRs to Ansible, Capistrano updates, etc.).</li>
      <li>Sticking with Karafka avoided excessive complexity.</li>
    </ul>
  </li>
  <li><strong>Redis for Message Storage</strong>
    <ul>
      <li>Why Redis?
        <ul>
          <li>faster than db</li>
          <li>with db we already had problems with too many connections</li>
        </ul>
      </li>
      <li>Created a new Kafka topic and extended the Karafka consumer.</li>
      <li>Karafka consumer, stored them in <strong>Redis lists</strong> - one_pipeline_list</li>
      <li>Used Redis/Ruby Interface - not all commands were available in Ruby due to wrapping native C++ functionality</li>
      <li>No expiration was set on the Redis list to ensure durability.</li>
      <li>Consulted the DevOps team to confirm available Redis and Kafka storage capacity.</li>
    </ul>
  </li>
  <li><strong>Backup and Retry Mechanism</strong>
    <ul>
      <li>Introduced a <code class="language-plaintext highlighter-rouge">backup_list</code> alongside the main Redis list to ensure robustness.</li>
      <li>When processing messages:
        <ul>
          <li>Moved them from <code class="language-plaintext highlighter-rouge">main_list</code> → <code class="language-plaintext highlighter-rouge">backup_list</code>.</li>
          <li>Performed merging and queued Sidekiq jobs for ES updates.</li>
          <li>Only after successful execution were messages removed from <code class="language-plaintext highlighter-rouge">backup_list</code>.</li>
        </ul>
      </li>
      <li>This ensured:
        <ul>
          <li><strong>No data loss on process failure (e.g., Sidekiq termination with kill -9 from bash).</strong></li>
          <li><strong>New data wouldn’t mix with partially processed data.</strong></li>
        </ul>
      </li>
    </ul>
  </li>
</ol>

<h2 id="results"><strong>Results</strong></h2>

<ul>
  <li><strong>Reduced ES upsert volume</strong>, leading to more predictable query performance.
    <ul>
      <li>logged it using Rollbar with additional data as upsert_records divided by input_records_count</li>
    </ul>
  </li>
  <li><strong>Faster query execution times</strong></li>
  <li><strong>Easier debugging &amp; failure recovery</strong>, thanks to Redis-backed retry mechanisms.</li>
  <li><strong>Smooth transition from the old system</strong>, as we could toggle between methods.</li>
</ul>

<p>There was no fancy checking of everything with hard-data. After implementation we added more vectors data to product records in ES and had no problems with ES after this. We didn’t need to think about - will ES failing in prime time? One Pipeline took responsibility of managing workload of ES.</p>

<h2 id="multiple-deployments"><strong>Multiple Deployments</strong></h2>

<p>Most of the changes in this technical challenge called OnePipeline were not depended on each other. As far as I remember I divided this into following PRs:</p>

<ul>
  <li>messages producer change to add new topic to the list</li>
  <li>new Karafka consumer with putting message on Redis List</li>
  <li>OnePipeline worker - to deep merge data</li>
  <li>Change each invoke of Upserting ES data to produce it to one-pipeline topic.</li>
</ul>

<p>MVP of this challenge was to upsert data in one place. Later on we refactor it to handle deletions and additional version of ES7. Also there were talks how to approach this problem. Especially with Karafka and how to get many messages once.</p>

<p>Yes, each change was separate deployment. Deployment took about 3-7 minutes :)</p>]]></content><author><name></name></author><category term="technical" /><category term="elasticsearch" /><summary type="html"><![CDATA[Our Elasticsearch (ES) cluster was experiencing unpredictable query slowdowns due to irregular upsert volumes. The slowdown occurred mostly during increased write times. We seen it on Graph. We knew what workers were running at those times. Grafana was used for monitoring.]]></summary></entry></feed>