<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Myungwoo Song</title>
    <description>The latest articles on DEV Community by Myungwoo Song (@erados).</description>
    <link>https://dev.to/erados</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1147878%2F34d4bc82-d902-4166-80c2-f07d7ac1e5ec.jpeg</url>
      <title>DEV Community: Myungwoo Song</title>
      <link>https://dev.to/erados</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/erados"/>
    <language>en</language>
    <item>
      <title>Optimizing Ruby on Rails Serializers: Efficient Hash Unpacking in Serializer</title>
      <dc:creator>Myungwoo Song</dc:creator>
      <pubDate>Sat, 02 Dec 2023 09:38:09 +0000</pubDate>
      <link>https://dev.to/erados/optimizing-ruby-on-rails-serializers-efficient-hash-unpacking-in-serializer-4a0f</link>
      <guid>https://dev.to/erados/optimizing-ruby-on-rails-serializers-efficient-hash-unpacking-in-serializer-4a0f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the world of Ruby on Rails development, serializers play a crucial role in transforming ActiveRecord objects into JSON formats suitable for client-side consumption. However, while invaluable, serializers can sometimes introduce performance bottlenecks. In this article, I share my experience in overcoming a specific challenge: efficiently unpacking results from a resource-intensive method.&lt;/p&gt;

&lt;h2&gt;
  
  
  The performance issues
&lt;/h2&gt;

&lt;p&gt;Imagine a scenario common in high-traffic web applications, like an e-commerce platform, where efficiency in data handling is not just a luxury but a necessity. You have a method in your Rails model that needs to be invoked, and its results - a collection of various fields - must be flattened.&lt;/p&gt;

&lt;p&gt;Here's the method in question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# In a Rails Model&lt;/span&gt;
  &lt;span class="c1"&gt;# @return [Hash]&lt;/span&gt;
  &lt;span class="c1"&gt;#  [Number] total_paid_price&lt;/span&gt;
  &lt;span class="c1"&gt;#  [Number] total_unpaid_price&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;total_book_prices&lt;/span&gt;
  &lt;span class="n"&gt;query_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;book_suppliers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;book: :invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"CASE WHEN invoices.stage &amp;lt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:approved&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; THEN 'unpaid' ELSE 'paid' END"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"invoices.total_price"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;total_paid_price: &lt;/span&gt;&lt;span class="n"&gt;query_result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"paid"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;total_unpaid_price: &lt;/span&gt;&lt;span class="n"&gt;query_result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"unpaid"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A naive approach might be to simply call this method twice within your serializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SupplierListSerializer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Serializer&lt;/span&gt;
  &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_paid_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_unpaid_price&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;total_paid_price&lt;/span&gt;
    &lt;span class="n"&gt;total_book_prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:total_paid_price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;total_unpaid_price&lt;/span&gt;
    &lt;span class="n"&gt;total_book_prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:total_unpaid_price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this leads to redundant database queries, a cardinal sin in performance-sensitive applications. Particularly with complex queries or large datasets, this inefficiency can significantly impact performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution I found
&lt;/h2&gt;

&lt;p&gt;To circumvent this problem, I implemented a caching strategy within the serializer itself. By storing the result of the first method call in an instance variable, subsequent calls can use this cached result instead of hitting the database again. Here's how it looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SupplierListSerializer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Serializer&lt;/span&gt;
  &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:number_of_books&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_paid_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_unpaid_price&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;total_paid_price&lt;/span&gt;
    &lt;span class="n"&gt;total_book_prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:total_paid_price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;total_unpaid_price&lt;/span&gt;
    &lt;span class="n"&gt;total_book_prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:total_unpaid_price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="c1"&gt;# Caching the result in an instance variable&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;total_book_prices&lt;/span&gt;
    &lt;span class="vi"&gt;@total_book_prices&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;total_book_prices&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple yet effective change ensures that our method total_book_prices` is called only once per serializer instance, significantly reducing database load and improving overall performance.&lt;/p&gt;

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

&lt;p&gt;By implementing this caching technique, we've successfully navigated around one of the many performance pitfalls in Rails serializers. However, it's just the tip of the iceberg. There are other challenges, such as the infamous N+1 query issue, which can severely impact performance if not handled properly. In my next article, I'll delve into strategies to overcome this widespread issue.&lt;/p&gt;

&lt;p&gt;Thank you for reading, and I encourage you to share your experiences or alternative solutions in the comments below!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Automating `updated_at` Timestamps with `update_all` in Ruby on Rails</title>
      <dc:creator>Myungwoo Song</dc:creator>
      <pubDate>Thu, 16 Nov 2023 10:22:11 +0000</pubDate>
      <link>https://dev.to/erados/automating-updatedat-timestamps-with-updateall-in-ruby-on-rails-a5a</link>
      <guid>https://dev.to/erados/automating-updatedat-timestamps-with-updateall-in-ruby-on-rails-a5a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Ruby on Rails greatly simplifies many programming tasks, yet sometimes its behavior can diverge from expectations. A notable example is when using the &lt;code&gt;update_all&lt;/code&gt; method. This method, while efficient, does not automatically update the &lt;code&gt;updated_at&lt;/code&gt; column in a database record. This oversight can lead to difficulties in tracking changes, particularly when auditing data history. This article presents a practical solution to this issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Ruby's Handling of Modules and Classes
&lt;/h2&gt;

&lt;p&gt;Ruby's approach to modules and classes is fundamental to understanding the solution. In Ruby, a class can inherit features from a parent class and incorporate modules. This is achieved through a &lt;code&gt;super&lt;/code&gt; pointer in each class, which references its parent, and a &lt;code&gt;method_table&lt;/code&gt; that contains its methods. When a method is invoked, Ruby searches the &lt;code&gt;method_table&lt;/code&gt; and, if necessary, proceeds up the inheritance chain. Including a module into a class inserts the module's methods into this lookup process, allowing for flexible and powerful customization.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Art of Monkey Patching
&lt;/h2&gt;

&lt;p&gt;'Monkey patching' refers to dynamically modifying or extending a class. In our case, we want Ruby to execute custom code before the native &lt;code&gt;update_all&lt;/code&gt; method. This reverse lookup—checking our module first and then the original class—is made possible through the &lt;code&gt;prepend&lt;/code&gt; keyword. By prepending our module, &lt;code&gt;CustomUpdateAll&lt;/code&gt;, to &lt;code&gt;ActiveRecord::Relation&lt;/code&gt;, we ensure that our version of &lt;code&gt;update_all&lt;/code&gt; is found first. This technique is particularly useful in Rails, where code in &lt;code&gt;config/initializer&lt;/code&gt; is executed after the framework has loaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhanced &lt;code&gt;update_all&lt;/code&gt; Code
&lt;/h2&gt;

&lt;p&gt;I first want to acknowledge that this is based on and inspired by &lt;a href="https://gist.github.com/timm-oh/9b702a15f61a5dd20d5814b607dc411d" rel="noopener noreferrer"&gt;Choncou's Code&lt;/a&gt; with some slight modifications of my own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/initializer/custom_update_all.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;CustomUpdateAll&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Check if updates should modify the updated_at column&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:skip_touch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;column_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Merge our custom timestamp&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt; &lt;span class="c1"&gt;# Call the original update_all method&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Relation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CustomUpdateAll&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Further Exploration
&lt;/h2&gt;

&lt;p&gt;While this solution addresses hash-based updates, it can be expanded to handle strings and arrays. If you want, experiment and adapt the code to these formats, sharing your modifications and insights.&lt;/p&gt;

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

&lt;p&gt;In summary, this article detailed a method to ensure &lt;code&gt;updated_at&lt;/code&gt; is automatically updated when using &lt;code&gt;update_all&lt;/code&gt; in Ruby on Rails. This solution enhances data integrity and simplifies record auditing. Your feedback and experiences with this approach are warmly welcomed.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/timm-oh/9b702a15f61a5dd20d5814b607dc411d" rel="noopener noreferrer"&gt;Choncou's Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>database</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Managing Ruby's Memory Bloating In Sidekiq: Strategies and Solutions</title>
      <dc:creator>Myungwoo Song</dc:creator>
      <pubDate>Sat, 07 Oct 2023 07:27:30 +0000</pubDate>
      <link>https://dev.to/erados/how-to-detour-rubys-memory-bloating-in-sidekiq-17fc</link>
      <guid>https://dev.to/erados/how-to-detour-rubys-memory-bloating-in-sidekiq-17fc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Ruby, a versatile programming language, is known for its ease of use and flexibility. However, it also comes with its own set of challenges, particularly related to memory management. In this article, we'll talk about Ruby's memory handling, the issues it can pose, and strategies to mitigate them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ruby's Memory Architecture
&lt;/h2&gt;

&lt;p&gt;Ruby manages objects in two main places: &lt;strong&gt;Object Space&lt;/strong&gt; and &lt;strong&gt;Memory Arena&lt;/strong&gt;. Objects smaller than 24 bytes reside in Object Space, while larger objects are allocated to Memory Arena, with only their addresses stored in Object Space.&lt;/p&gt;

&lt;p&gt;Ruby, implemented in C, allocates memory to Memory Arena using &lt;code&gt;malloc&lt;/code&gt; in &lt;code&gt;glib.c&lt;/code&gt;. To prevent concurrency issues, each Memory Arena has a lock. However, this can lead to performance bottlenecks in multi-threaded programs. To address this, Ruby creates multiple Memory Arenas and assign one Memory Arena to certain thread, but this can result in memory bloat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we get the bloating?
&lt;/h2&gt;

&lt;p&gt;But why? Think about Sidekiq with multiple threads. Maximum 1 Memory Arena will be assigned to each thread instead of each thread waiting for it's turn to access a Memory Arena. So, more than needed Memory have to be created, leading to more Memory usage.&lt;/p&gt;

&lt;p&gt;Plus, there is another problem inside the allocator. It does not want to free the empty memory to the kernel. With these conditions altogether, We finally get the long lasting Memory Bloating!&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategies to Address Ruby's Memory Issues
&lt;/h2&gt;

&lt;p&gt;So, how can we deal with them? There are several strategies to tackle these memory problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Changing Memory Allocator&lt;/strong&gt;: Consider switching from the default &lt;code&gt;malloc&lt;/code&gt; allocator to an alternative like &lt;code&gt;jemalloc&lt;/code&gt;. Note that compatibility &lt;a href="https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/#:~:text=compatibility%20issues%20with%20Alpine%20Linux" rel="noopener noreferrer"&gt;issues&lt;/a&gt; may arise on Alpine-based systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setting Memory Arena Limits&lt;/strong&gt;: You can set a tighter limit on the number of Memory Arenas using &lt;code&gt;MALLOC_ARENA_MAX = 2&lt;/code&gt;. This can help mitigate concurrency-related performance issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Freeing Memory Not In Use&lt;/strong&gt;: Another potential solution is to address Ruby's reluctance to free memory after use. Check out this insightful &lt;a href="https://www.joyfulbikeshedding.com/blog/2019-03-14-what-causes-ruby-memory-bloat.html" rel="noopener noreferrer"&gt;article&lt;/a&gt; for more information on this approach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rerunning the Program&lt;/strong&gt;: There might be some companies hesitating to modify the magical environment variable using Apline-based docker image just like my case. Then, periodically restarting the program can be a solution too. I will concentrate on this solution below.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  Rerunning the Program as a Temporary Fix
&lt;/h1&gt;

&lt;p&gt;In some cases, a quick workaround involves periodically restarting your Ruby application. This can temporarily alleviate memory issues for especially those who are hesitating to manipulate the magical environment variable. However, it's not a fundamental solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory Challenges and Job Retries
&lt;/h2&gt;

&lt;p&gt;When dealing with Sidekiq containers, shutting them down can lead to unexpected job retries. Whenever a Sidekiq process shuts down, the jobs it was working on return to the Redis queue. When the process restarts, it reprocesses all the jobs, regardless of their previous progress.&lt;/p&gt;

&lt;p&gt;To address this side effect, consider implementing a generous shutdown function in your logic. This function ensures that jobs in progress are not retried unnecessarily. It's a crucial addition to managing memory issues in Sidekiq.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the Memory Management Solution
&lt;/h2&gt;

&lt;p&gt;Here's a high-level overview of the approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilize AWS EventBridge to run a function every 5-10 minutes.&lt;/li&gt;
&lt;li&gt;The function uses the AWS SDK to monitor the running-time of processes.&lt;/li&gt;
&lt;li&gt;The function pauses processes that have been running for an extended period using the TSTP &lt;a href="https://github.com/sidekiq/sidekiq/wiki/Signals" rel="noopener noreferrer"&gt;signal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;After the process completes its last job, the function terminates it using the TERM signal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional considerations include maintaining at least one running process, limiting the maximum number of processes, and implementing scaling logic.&lt;/p&gt;




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

&lt;p&gt;Ruby's memory management challenges are a common issue for developers, but they are not insurmountable. By understanding the fundamentals of Ruby's memory handling and implementing appropriate strategies, you can optimize the performance of your Ruby applications. If you've encountered similar challenges or have questions, feel free to share your experiences and seek assistance within the community.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.speedshop.co/2017/12/04/malloc-doubles-ruby-memory.html" rel="noopener noreferrer"&gt;Malloc Can Double Multi-threaded Ruby Program Memory Usage&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.joyfulbikeshedding.com/blog/2019-03-14-what-causes-ruby-memory-bloat.html" rel="noopener noreferrer"&gt;What causes Ruby memory bloat?&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>sidekiq</category>
      <category>memory</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
