avatarAckshaey Singh

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

2078

Abstract

and constructing the response requires complex queries and interactions with multiple services. Below, the <code>display_cards</code> action powers an infinite scroll list on the client. By implementing <code>expires_in 1.hour, public: true</code>, we essentially direct clients to retain and reuse their cached response for an hour. When users navigate back and forth, adding this cache control header reduces ~100ms round trip time from the client's perspective and diminishes request volume to our backend Redis cache by over 60%.</p><figure id="94ff"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*9G8hcg9CpSzSrrJK.png"><figcaption></figcaption></figure><div id="b7b1"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">ProductsController</span> < <span class="hljs-title class_ inherited__">ApplicationController</span> ... <span class="hljs-variable constant_">CLIENT_CACHE_EXPIRY_DURATION</span> = <span class="hljs-number">1</span>.hour ...

<span class="hljs-keyword">def</span> <span class="hljs-title function_">display_cards</span> <span class="hljs-comment"># ... expensive queries and requests to backend caches to build response</span>

expires_in <span class="hljs-variable constant_">CLIENT_CACHE_EXPIRY_DURATION</span>, <span class="hljs-symbol">public:</span> <span class="hljs-literal">true</span> <span class="hljs-comment"># Set the Cache-Control header</span>

respond_to <span class="hljs-keyword">do</span> |<span class="hljs-params">format</span>|
  format.json <span class="hljs-keyword">do</span>
    render <span class="hljs-symbol">json:</span> response, <span class="hljs-symbol">status:</span> <span class="hljs-symbol">:ok</span>, <span class="hljs-symbol">mimetype:</span> <span class="hljs-title class_">Mime</span>[<span class="hljs-symbol">:json</span>]
  <span class="hljs-keyword">end</span>

  format.protobuf <span class="hljs-keyword">do</span>
    render <span class="hljs-symbol">plain:</span> response.to_proto, <span class="hljs-symbol">

Options

status:</span> <span class="hljs-symbol">:ok</span>, <span class="hljs-symbol">mimetype:</span> <span class="hljs-title class_">Mime</span>[<span class="hljs-symbol">:protobuf</span>] <span class="hljs-keyword">end</span> <span class="hljs-keyword">end</span> <span class="hljs-keyword">end</span> <span class="hljs-keyword">end</span></pre></div><figure id="c208"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*O3QFVE90GLWnsZ4D.png"><figcaption></figcaption></figure><h1 id="66c8">The Subtleties of expires_in</h1><p id="7bfa">When utilizing <code>expires_in</code> in your controller actions, it's pivotal to understand its various options:</p><ul><li><b>Time Duration</b>: This determines the freshness duration. Be it <code>30.minutes</code> or <code>1.day</code>, ensure it matches your application's data refresh cycle.</li><li><b>Public/Private Directive</b>: <code>public: true</code> indicates any cache, including CDNs, can store the response. In contrast, <code>private: true</code> refers to user-specific data that should only be cached at the user level.</li><li><b>Other Directives</b>: Directives like <code>must_revalidate</code> can be used for nuanced cache control. With <code>must_revalidate</code>, once data becomes stale, it must be re-validated with the server before being reused.</li></ul><p id="8850">And there you have it! I’ve deliberately left out the many other splendid backend caching techniques integrated into Rails and those used by the <code>display_cards</code> endpoint above; those will be the subject of another post. Before signing off, here are some plugs for my projects:</p><p id="7bd1"><i>Preparing for a software engineering interview but loathe grinding LeetCode? I crafted <a href="https://firecode.io/">Firecode.io</a> precisely for that reason. Give it a whirl!</i></p><p id="fd90"><i>Fancy buying furniture at 20–30% designer and trade discounts without the need to hire an interior designer? Swing by <a href="https://designerdiscount.club/">Designer Discount Club</a>!</i></p></article></body>

Harnessing Client-Side Caching in Rails: The Power of `expires_in`

In your journey as a software developer, you’ll encounter myriad tools and techniques designed to optimize and streamline web applications. One such tool, often overlooked, is client-side caching. As backend and full-stack engineers, we spend hours crafting complex caching layers on the backend. However, we often overlook the most effective caching technique: having the request never reach the backend! Let’s delve into how requests get cached on the client using the Cache-Control header.

Cache Control Header

At the core of client-side caching is the HTTP Cache-Control header. This header offers directives to browsers (and other caching agents) about how they should cache the content and when to consider it stale.

The most common directives include:

  • max-age: Specifies the number of seconds the response remains fresh.
  • no-cache: Directs caching agents to revalidate with the server before using the cached version.
  • public/private: public means that any cache, including CDNs, can store the response. private ensures the response is user-specific and only cached at the end-user level.

By setting the appropriate cache control headers, developers can steer the caching behavior of browsers and intermediaries, thereby optimizing both server load and user experience.

Rails expires_in in Controller Actions

In the Rails ecosystem, the expires_in method is our key to effortlessly managing the cache control header. Within the context of Rails actions, using expires_in sets the Cache-Control header on the HTTP response.

Take, for instance, an application like Designer Discount Club I’m currently building. The product data updates roughly once a day, and constructing the response requires complex queries and interactions with multiple services. Below, the display_cards action powers an infinite scroll list on the client. By implementing expires_in 1.hour, public: true, we essentially direct clients to retain and reuse their cached response for an hour. When users navigate back and forth, adding this cache control header reduces ~100ms round trip time from the client's perspective and diminishes request volume to our backend Redis cache by over 60%.

class ProductsController < ApplicationController
  ...
  CLIENT_CACHE_EXPIRY_DURATION = 1.hour
  ...

  def display_cards
    # ... expensive queries and requests to backend caches to build `response`
    
    expires_in CLIENT_CACHE_EXPIRY_DURATION, public: true # Set the Cache-Control header

    respond_to do |format|
      format.json do
        render json: response, status: :ok, mimetype: Mime[:json]
      end

      format.protobuf do
        render plain: response.to_proto, status: :ok, mimetype: Mime[:protobuf]
      end
    end
  end
end

The Subtleties of expires_in

When utilizing expires_in in your controller actions, it's pivotal to understand its various options:

  • Time Duration: This determines the freshness duration. Be it 30.minutes or 1.day, ensure it matches your application's data refresh cycle.
  • Public/Private Directive: public: true indicates any cache, including CDNs, can store the response. In contrast, private: true refers to user-specific data that should only be cached at the user level.
  • Other Directives: Directives like must_revalidate can be used for nuanced cache control. With must_revalidate, once data becomes stale, it must be re-validated with the server before being reused.

And there you have it! I’ve deliberately left out the many other splendid backend caching techniques integrated into Rails and those used by the display_cards endpoint above; those will be the subject of another post. Before signing off, here are some plugs for my projects:

Preparing for a software engineering interview but loathe grinding LeetCode? I crafted Firecode.io precisely for that reason. Give it a whirl!

Fancy buying furniture at 20–30% designer and trade discounts without the need to hire an interior designer? Swing by Designer Discount Club!

Software Development
Web Development
Ruby on Rails
Tutorial
Performance
Recommended from ReadMedium