<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ cache - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ cache - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 30 May 2026 08:56:00 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/cache/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Cache Golang API Responses for High Performance ]]>
                </title>
                <description>
                    <![CDATA[ Go makes it easy to build APIs that are fast out of the box. But as usage grows, speed at the language level is not enough. If every request keeps hitting the database, crunching the same data, or serializing the same JSON over and over, latency cree... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-cache-golang-api-responses/</link>
                <guid isPermaLink="false">68ef76f4e9381bb61f442e34</guid>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ caching ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cache ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Temitope Oyedele ]]>
                </dc:creator>
                <pubDate>Wed, 15 Oct 2025 10:27:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760523799795/3b48a898-77fc-4983-90b5-6e21e8019f1e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Go makes it easy to build APIs that are fast out of the box. But as usage grows, speed at the language level is not enough. If every request keeps hitting the database, crunching the same data, or serializing the same JSON over and over, latency creeps up and throughput suffers. Caching is the tool that keeps performance high by storing work that has already been done so that future requests can reuse it instantly. Let’s look at four practical ways to cache APIs in Go, each explained with an analogy and backed by simple code you can adapt.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-response-caching-with-local-and-redis-storage">Response Caching with Local and Redis Storage</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-database-query-result-caching">Database Query Result Caching</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-http-caching-with-etag-and-cache-control">HTTP Caching with ETag and Cache-Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-stale-while-revalidate-with-background-refresh">Stale-While-Revalidate with Background Refresh</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h2 id="heading-response-caching-with-local-and-redis-storage">Response Caching with Local and Redis Storage</h2>
<p>When the process of generating an API response becomes expensive, the fastest solution is to store the entire response. Think of a coffee shop during the morning rush. If every customer orders the same latte, the barista could grind beans and steam milk for each order, but the line would move slowly. A smarter move is to brew a pot once and pour from it repeatedly. To handle both speed and scale, the shop keeps a small pot at the counter for instant pours and a larger urn in the back for refills. In software terms, the counter pot is a local in-memory cache such as <a target="_blank" href="https://pkg.go.dev/github.com/dgraph-io/ristretto">Ristretto</a> or <a target="_blank" href="https://pkg.go.dev/github.com/allegro/bigcache">BigCache</a>, and the urn is <a target="_blank" href="https://redis.io/">Redis,</a> which allows multiple API servers to share the same cached responses.</p>
<p>In Go, this two-tier setup usually follows a cache-aside pattern: look in local memory first, fall back to Redis if needed, and only compute the result when both layers miss. Once computed, the value is saved in Redis for everyone and in memory for immediate reuse on the next call.</p>
<pre><code class="lang-go">val, ok := local.Get(key)
<span class="hljs-keyword">if</span> !ok {
    val, err = rdb.Get(ctx, key).Result()
    <span class="hljs-keyword">if</span> err == redis.Nil {
        val = computeResponse() <span class="hljs-comment">// expensive DB or logic</span>
        _ = rdb.Set(ctx, key, val, <span class="hljs-number">60</span>*time.Second).Err()
    }
    local.Set(key, val, <span class="hljs-number">1</span>)
}
w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
w.Write([]<span class="hljs-keyword">byte</span>(val))
</code></pre>
<p>In the code above, the first attempt is to retrieve the response from the local cache, which returns instantly if the key or data exists. If not found, it queries Redis as the second layer. If Redis also returns nothing, the expensive computation runs and its result is stored in Redis with a sixty seconds expiration so other services can access it, then placed in the local cache for immediate reuse. After which, the response is written back to the client as JSON.</p>
<p>This gives you the best of both worlds: lightning-fast responses for repeat calls and a consistent cache across all your API servers.</p>
<h2 id="heading-database-query-result-caching">Database Query Result Caching</h2>
<p>Sometimes the API itself is simple but the real cost hides in the database. Imagine a newsroom waiting for election results. If every editor keeps calling the counting office for the same numbers, the phone lines may jam. Instead, one reporter calls once, writes the result on a board, and every editor copies from there. The board is the cache, and it saves both time and pressure on the office.</p>
<p>In Go, you can apply the same principle by caching query results. Rather than hitting the database for each identical request, you store the result in Redis with a key that represents the query intent. When the next request comes in, you pull from Redis, skip the database, and respond faster.</p>
<pre><code class="lang-go">key := fmt.Sprintf(<span class="hljs-string">"q:UserByID:%d"</span>, id)
<span class="hljs-keyword">if</span> b, err := rdb.Get(ctx, key).Bytes(); err == <span class="hljs-literal">nil</span> {
    <span class="hljs-keyword">var</span> u User
    _ = json.Unmarshal(b, &amp;u)
    <span class="hljs-keyword">return</span> u
}

u, _ := repo.GetUser(ctx, id) <span class="hljs-comment">// real DB call</span>
bb, _ := json.Marshal(u)
_ = rdb.Set(ctx, key, bb, <span class="hljs-number">2</span>*time.Minute).Err()
<span class="hljs-keyword">return</span> u
</code></pre>
<p>Here, we construct a cache key that uniquely identifies the query using the user ID, then attempts to fetch the serialized result from Redis. If the key exists, it deserializes the bytes back into a <code>User</code> struct and returns immediately without touching the database. On a cache miss, it executes the actual database query through the repository, serializes the <code>User</code> object to JSON, stores it in Redis with a two-minute expiration, and returns the result.</p>
<p>This pattern dramatically reduces database load and response time for read-heavy APIs, but you must remember to clear or refresh entries when data changes, or set short time-to-live values to keep results reasonably fresh.</p>
<h2 id="heading-http-caching-with-etag-and-cache-control">HTTP Caching with ETag and Cache-Control</h2>
<p>Not all caching has to happen inside the server. The HTTP standard already provides tools that let clients or CDNs reuse responses. By setting headers like <code>ETag</code> and <code>Cache-Control</code>, you can tell the client whether the response has changed. If nothing is new, the client keeps its own copy and the server only sends a lightweight 304 response.</p>
<p>It is similar to a manager posting notices on an office board. Each sheet carries a small stamp. Employees compare the stamp against the one they already have. If it matches, they know their copy is still valid and skip taking a new one. Only when the stamp changes do they replace it.</p>
<p>In Go this is straightforward. Compute an ETag from the response body, compare it with what the client sends, and decide whether to return the full payload or just the 304.</p>
<pre><code class="lang-go">etag := computeETag(responseBytes)
<span class="hljs-keyword">if</span> match := r.Header.Get(<span class="hljs-string">"If-None-Match"</span>); match == etag {
    w.WriteHeader(http.StatusNotModified)
    <span class="hljs-keyword">return</span>
}

w.Header().Set(<span class="hljs-string">"ETag"</span>, etag)
w.Header().Set(<span class="hljs-string">"Cache-Control"</span>, <span class="hljs-string">"public, max-age=60"</span>)
w.Write(responseBytes)
</code></pre>
<p>The code above generates an ETag, which is a fingerprint or hash of the response content, then checks if the client sent an <code>If-None-Match</code> header with a matching ETag from a previous request. If the ETags match, the content hasn't changed, so the server responds with a 304 Not Modified status and sends no body, saving bandwidth. When the ETags don't match or the client has no cached version, the server attaches the new ETag and a <code>Cache-Control</code> header that allows public caching for sixty seconds, then sends the full response.</p>
<p>This approach reduces bandwidth, lowers CPU usage, and pairs well with CDNs that can cache and serve responses directly.</p>
<h2 id="heading-stale-while-revalidate-with-background-refresh">Stale-While-Revalidate with Background Refresh</h2>
<p>There are cases where serving slightly old data is acceptable if it keeps the API fast. Stock dashboards, analytics summaries, or feed endpoints often fit this model. Instead of making users wait for fresh data on every request, you can serve the cached value immediately and refresh it quietly in the background. This technique is called Stale-While-Revalidate.</p>
<p>Picture a stock ticker screen in a lobby. The numbers may be a few seconds behind, but they are still useful to anyone glancing at the board. Meanwhile, a background process fetches the latest figures and updates the ticker. The reader never stares at a blank screen and the system stays responsive even during spikes.</p>
<p>In Go, this can be built by storing not just the cached data but also timestamps that define when the data is fresh, when it can still be served as stale, and when it must be recomputed. The <code>singleflight</code> package helps ensure that only one goroutine does the refresh work, preventing a dogpile of updates.</p>
<pre><code class="lang-go">entry := getEntry(key) <span class="hljs-comment">// {data, freshUntil, staleUntil}</span>
<span class="hljs-keyword">switch</span> {
<span class="hljs-keyword">case</span> time.Now().Before(entry.freshUntil):
    <span class="hljs-keyword">return</span> entry.data
<span class="hljs-keyword">case</span> time.Now().Before(entry.staleUntil):
    <span class="hljs-keyword">go</span> refreshSingleflight(key) <span class="hljs-comment">// background refresh</span>
    <span class="hljs-keyword">return</span> entry.data
<span class="hljs-keyword">default</span>:
    <span class="hljs-keyword">return</span> refreshSingleflight(key) <span class="hljs-comment">// must refresh now</span>
}
</code></pre>
<p>Here, the code retrieves a cache entry containing the data along with two timestamps marking the freshness and staleness boundaries. If the current time falls before the fresh threshold, the data is considered fully fresh and returned immediately. If time has passed the fresh threshold but remains within the stale window, the code returns the slightly outdated data instantly while launching a background goroutine to refresh it asynchronously, ensuring the next request gets updated information. Once time exceeds even the stale boundary, the data is too old to serve, so the code blocks and performs a synchronous refresh before returning.</p>
<p>This keeps latency low while still ensuring the cache updates regularly, a balance between freshness and performance.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Caching is not a single tactic but a set of strategies that fit different needs. Full response caching eliminates repeat work at the top level. Query result caching protects the database from repeated load. HTTP caching leverages the protocol to cut down data transfer. Stale-While-Revalidate strikes a compromise that favors speed without leaving data stale for too long.</p>
<p>In practice, these approaches are often layered. A Go API might use local memory and Redis for responses, apply query-level caching for hot tables, and set ETags so clients avoid unnecessary downloads. With the right mix, you can cut latency by orders of magnitude, handle far more traffic, and save both compute and database resources.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Memcached Crash Course ]]>
                </title>
                <description>
                    <![CDATA[ Memcached is an important technology for back end developers to understand. It is a distributed memory caching system, primarily used to speed up web applications by reducing database load. It stores data in memory, allowing quicker access compared t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/memcached-crash-course/</link>
                <guid isPermaLink="false">66b205bd125aeccef6f65cfd</guid>
                
                    <category>
                        <![CDATA[ cache ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Mon, 08 Jan 2024 18:02:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/memcached.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Memcached is an important technology for back end developers to understand. It is a distributed memory caching system, primarily used to speed up web applications by reducing database load. It stores data in memory, allowing quicker access compared to traditional database-driven methods.</p>
<p>We just published a Memcached crash course on the freeCodeCamp.org Youtbue channel. This course, designed for both beginners and intermediate learners, delves into the architecture and design choices of Memcached. It provides practical hands-on experience with Docker, Telnet, and Node.js, making it an invaluable resource for anyone looking to enhance their web application performance. Hussein Nasser developed this course.</p>
<p>The course explains the key-value store mechanism of Memcached, emphasizing its simplicity and efficiency in handling web application data.</p>
<h3 id="heading-course-highlights">Course Highlights</h3>
<ol>
<li><strong>Understanding Memcached's Architecture</strong>: Deep insights into Memcached's design, including memory management and Least Recently Used (LRU) caching policy.</li>
<li><strong>Practical Demonstrations</strong>: Utilizing Docker for setting up a Memcached environment, Telnet for interaction, and Node.js for integrating Memcached into web applications.</li>
<li><strong>Advanced Concepts</strong>: Exploring threading, connections, read and write operations, collision handling, and locking mechanisms.</li>
<li><strong>Distributed Caching</strong>: Learning how Memcached enables distributed caching, enhancing scalability and performance.</li>
</ol>
<p>Here are the sections in this course:</p>
<ul>
<li>What is Memcached?</li>
<li>Memory management</li>
<li>LRU</li>
<li>Threading and Connections</li>
<li>Read Example</li>
<li>Write Example</li>
<li>Write and Read collisions </li>
<li>Locking</li>
<li>Distributed Cache</li>
<li>Memcached with Docker/Telnet/NodeJS</li>
<li>Spin up a Memcached Docker container and telnet</li>
<li>Memcached and NodeJS</li>
<li>Four Memached Servers with NodeJS</li>
<li>Summary</li>
</ul>
<h3 id="heading-why-memcached">Why Memcached?</h3>
<p>Memcached is essential for web developers looking to optimize application performance. It offers rapid data access and reduces database load, crucial for high-traffic websites. This course provides the necessary skills to implement Memcached effectively, ensuring a more responsive and efficient web application experience.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Whether you're a beginner or have some experience, this course equips you with the knowledge to effectively implement and manage a Memcached system in your web applications.</p>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/VhM2ByShhzE">the freeCodeCamp.org YouTube channel</a> (1-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/VhM2ByShhzE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Docker Cache – How to Do a Clean Image Rebuild and Clear Docker's Cache ]]>
                </title>
                <description>
                    <![CDATA[ By Sebastian Sigl Containers enable you to package your application in a portable way that can run in many environments. The most popular container platform is Docker.  This tutorial will explain how to use the Docker build cache to your advantage. D... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/docker-cache-tutorial/</link>
                <guid isPermaLink="false">66d460f08812486a37369d56</guid>
                
                    <category>
                        <![CDATA[ cache ]]>
                    </category>
                
                    <category>
                        <![CDATA[ containers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 28 Mar 2022 18:51:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/03/docker-cache-guide.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sebastian Sigl</p>
<p>Containers enable you to package your application in a portable way that can run in many environments. The most popular container platform is <a target="_blank" href="https://www.docker.com/">Docker</a>. </p>
<p>This tutorial will explain how to use the Docker build cache to your advantage.</p>
<h2 id="heading-docker-build-cache">Docker Build Cache</h2>
<p>Building images should be fast, efficient, and reliable. The concept of Docker images comes with immutable layers. Every command you execute results in a new layer that contains the changes compared to the previous layer. </p>
<p>All previously built layers are cached and can be reused. But, if your installation depends on external resources, the Docker cache can cause issues.</p>
<h2 id="heading-how-to-leverage-the-docker-build-cache">How to Leverage the Docker Build Cache</h2>
<p>To understand Docker build-cache issues, let’s build a simple custom <a target="_blank" href="https://nginx.org/en/">nginx</a> Docker application. Before you build the image, create a Dockerfile that updates libraries and adds a custom startpage:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> nginx:<span class="hljs-number">1.21</span>.<span class="hljs-number">6</span>

<span class="hljs-comment"># Update all packages</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; apt-get -y upgrade</span>

<span class="hljs-comment"># Use a custom startpage</span>
<span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">'&lt;html&gt;&lt;bod&gt;My Custom Startpage&lt;/body&gt;&lt;/html&gt;'</span> &gt; /usr/share/nginx/html/index.html</span>
</code></pre>
<p>You can now build the Docker image:</p>
<pre><code class="lang-shell">$  docker build -t my-custom-nginx .

=&gt; [1/3] FROM docker.io/library/nginx:1.21.6@sha256:e12...  5.8s
=&gt; [2/3] RUN apt-get update &amp;&amp; apt-get -y upgrade           3.6s
=&gt; [3/3] RUN echo '&lt;html&gt;&lt;bod&gt;My Custom Startpage...        0.2s

=&gt; exporting to image                                       0.1s
=&gt; exporting layers                                         0.1s
=&gt; writing image                                            0.0s
=&gt; naming to docker.io/library/my-custom-nginx

[+] Building 11.3s (7/7) FINISHED
</code></pre>
<p>In this example, I removed some output for readability. If you build the image the first time, you see that it takes quite some time, in my case <code>11.3s</code>. </p>
<p>One long executing step is <code>apt-get update &amp;&amp; apt-get -y upgrade</code> depending on how many dependencies are updated and how fast your internet speed is. It checks for package updates on the operation system and installs them if available.</p>
<p>Now, you execute it again, and you benefit from the Docker build cache:</p>
<pre><code class="lang-shell">$ docker build -t my-custom-nginx .

=&gt; [1/3] FROM docker.io/library/nginx:1.21.6@sha256:e1211ac1…   0.0s
=&gt; CACHED [2/3] RUN apt-get update &amp;&amp; apt-get -y upgrade        0.0s
=&gt; CACHED [3/3] RUN echo '&lt;html&gt;&lt;bod&gt;My Custom Startpage...     0.0s

=&gt; exporting to image                                           0.0s
=&gt; exporting layers                                             0.0s
=&gt; writing image                                                0.0s
=&gt; naming to docker.io/library/my-custom-nginx

Building 1.1s (7/7) FINISHED
</code></pre>
<p>This time, the image build is very fast because it can reuse all previously built images. When you customize your startpage in the Dockerfile, you see how the caching behavior is affected:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> nginx:<span class="hljs-number">1.21</span>.<span class="hljs-number">6</span>

<span class="hljs-comment"># Update all packages</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; apt-get -y upgrade</span>

<span class="hljs-comment"># Use a custom startpage</span>
<span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">'&lt;html&gt;&lt;bod&gt;New Startpage&lt;/body&gt;&lt;/html&gt;'</span> &gt; /usr/share/nginx/html/index.html</span>
</code></pre>
<p>Now, build the image again:</p>
<pre><code class="lang-shell">$ docker build -t my-custom-nginx .

=&gt; [1/3] FROM docker.io/library/nginx:1.21.6@sha256:e1211ac1…   0.0s
=&gt; CACHED [2/3] RUN apt-get update &amp;&amp; apt-get -y upgrade        0.0s
=&gt; [3/3] RUN echo '&lt;html&gt;&lt;bod&gt;My Custom Startpage...            0.2s

=&gt; exporting to image                                           0.0s
=&gt; exporting layers                                             0.0s
=&gt; writing image                                                0.0s
=&gt; naming to docker.io/library/my-custom-nginx

Building 2.1s (7/7) FINISHED
</code></pre>
<p>This time it only rebuilt the last layer because it recognized that the <code>RUN</code> command had changed. But, it reused the intense 2nd build step and did not update operation system dependencies.</p>
<p>The caching behavior is intelligent. Once 1 step needs to rebuild, every subsequent step is built again. Therefore, it’s good to put frequently changing parts at the end of a <code>Dockerfile</code> to reuse previous build layers.</p>
<p>Still, maybe you want to force a rebuild of a cached layer to force a package update. Forcing a rebuild can be necessary because you want to keep your application safe and use the newest updates when available.</p>
<h2 id="heading-how-to-use-the-docker-build-no-cache-option">How to Use the Docker Build <code>--no-cache</code> Option</h2>
<p>There can be different reasons for disabling the build-cache. You can rebuild the image from the base image without using cached layers by using the <code>--no-cache</code> option.</p>
<pre><code class="lang-shell">$ docker build -t my-custom-nginx .

=&gt; CACHED [1/3] FROM docker.io/library/nginx:1.21.6@sha256:...  0.0s
=&gt; [2/3] RUN apt-get update &amp;&amp; apt-get -y upgrade               3.5s
=&gt; [3/3] RUN echo '&lt;html&gt;&lt;bod&gt;My Custom Startpage...            0.2s

=&gt; exporting to image                                           0.1s
=&gt; exporting layers                                             0.0s
=&gt; writing image                                                0.0s
=&gt; naming to docker.io/library/my-custom-nginx

Building 5.5s (7/7) FINISHED
</code></pre>
<p>New layers were constructed and used. The <code>docker build</code> runs both commands this time, which comes with an all-or-nothing approach. Either you provide the <code>--no-cache</code> option that executes all commands, or you will cache as much as possible.</p>
<h2 id="heading-how-to-use-docker-arguments-for-cache-busting">How to Use Docker Arguments for Cache-Busting</h2>
<p>Another option allows providing a little starting point in the Dockerfile. You need to edit your Dockerfile like this:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> nginx:<span class="hljs-number">1.21</span>.<span class="hljs-number">6</span>

<span class="hljs-comment"># Update all packages</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; apt-get -y upgrade</span>

<span class="hljs-comment"># Custom cache invalidation</span>
<span class="hljs-keyword">ARG</span> CACHEBUST=<span class="hljs-number">1</span>

<span class="hljs-comment"># Use a custom startpage</span>
<span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">'&lt;html&gt;&lt;bod&gt;New Startpage&lt;/body&gt;&lt;/html&gt;'</span> &gt; /usr/share/nginx/html/index.html</span>
</code></pre>
<p>You add a <code>CACHEBUST</code> argument to your Dockerfile at the location you want to enforce a rebuild. Now, you can build the Docker image and provide an always different value that causes all following commands to rerun:</p>
<pre><code class="lang-shell">$ docker build -t my-custom-nginx --build-arg CACHEBUST=$(date +%s) .

=&gt; [1/3] FROM docker.io/library/nginx:1.21.6@sha256:e1211ac1...    0.0s
=&gt; CACHED [2/3] RUN apt-get update &amp;&amp; apt-get -y upgrade           0.0s
=&gt; [3/3] RUN echo '&lt;html&gt;&lt;bod&gt;My Custom Startpage...               0.3s

=&gt; exporting to image                                              0.0s
=&gt; exporting layers                                                0.0s
=&gt; writing image                                                   0.0s
=&gt; naming to docker.io/library/my-custom-nginx

Building 1.0s (7/7) FINISHED
</code></pre>
<p>By providing <code>--build-arg CACHEBUST=$(date +%s)</code>, you set the parameter to an always different value that causes all following layers to rebuild.</p>
<h2 id="heading-summary">Summary</h2>
<p>Docker’s build-cache is a handy feature. It speeds up Docker builds due to reusing previously created layers. </p>
<p>You can use the  <code>--no-cache</code> option to disable caching or use a custom Docker build argument to enforce rebuilding from a certain step.</p>
<p>Understanding the Docker build cache is powerful and will make you more efficient in building your Docker container.</p>
<p>I hope you enjoyed this article.</p>
<p>If you liked it and feel the need to give me a round of applause or just want to get in touch, <a target="_blank" href="https://twitter.com/sesigl">follow me on Twitter</a>.</p>
<p>I work at eBay Kleinanzeigen, one of the world’s biggest classified companies. By the way, <a target="_blank" href="http://ebay-kleinanzeigen.de/careers">we are hiring</a>!</p>
<h2 id="heading-references">References</h2>
<ul>
<li><a target="_blank" href="https://www.geeksforgeeks.org/docker-arg-instruction/">Docker arg instruction</a></li>
<li><a target="_blank" href="https://stackoverflow.com/questions/35134713/disable-cache-for-specific-run-commands">Stackoverflow: Disable Cache for specific RUN commands</a></li>
<li><a target="_blank" href="https://www.baeldung.com/linux/docker-build-cache">Baeldung: How the Docker Build Cache Works and When Not to Use it</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Cached Data? What does Clear Cache Mean and What Does it Do? ]]>
                </title>
                <description>
                    <![CDATA[ By Jeff M Lowery First, what's a cache? In general terms, a cache (pronounced "cash") is a type of repository. You can think of a repository as a storage depot. In the military, this would be to hold weapons, food, and other supplies needed to carry ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-cached-data/</link>
                <guid isPermaLink="false">66d45f8d868774922c884fee</guid>
                
                    <category>
                        <![CDATA[ cache ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 06 Mar 2020 20:51:16 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9c44740569d1a4ca3110.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jeff M Lowery</p>
<h1 id="heading-first-whats-a-cache">First, what's a cache?</h1>
<p>In general terms, a <a target="_blank" href="https://www.merriam-webster.com/dictionary/cache">cache</a> (pronounced "cash") is a type of repository. You can think of a repository as a storage depot. In the military, this would be to hold weapons, food, and other supplies needed to carry forward a mission.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/A-simplified-diagram-of-the-cold-chain-logistics-network.png" alt="Image" width="600" height="400" loading="lazy">
<em>A military distribution network</em></p>
<p>In computer science, these "supplies" are termed resources, where the resources are scripts, code, and document content. The latter is sometimes more specifically referred to as "assets" such as text, static data, media, and hyperlinks, but here I'll just use the one term <em>resources</em>.</p>
<h2 id="heading-the-distinction-between-a-cache-and-other-types-of-repositories">The distinction between a cache and other types of repositories</h2>
<p>A cache's primary purpose is to speed up retrieval of web page resources, decreasing page load times. Another critical aspect of a cache is to ensure that it contains relatively fresh data. </p>
<p>This article will cover two prevalent methods of caching: <strong>browser caching</strong> and <strong>Content Delivery Networks</strong> (CDNs).</p>
<p>Besides caches, other repositories come into play in web architectures; often these are designed to hold vast troves of data. They are not as focussed, though, on retrieval performance. </p>
<p>For example, Amazon Glacier is a data repository that is designed to store data cheaply, but not retrieve it quickly. An SQL database, on the other hand, is designed to be flexible, up-to-date, and fast, but is seldom cheap and not usually as fast as a cache.</p>
<h1 id="heading-the-browser-cache-a-memory-cache">The Browser Cache: a memory cache</h1>
<p>A <a target="_blank" href="https://www.geeksforgeeks.org/cache-memory-in-computer-organization/">memory cache</a> stores resources locally on the computer where the browser is running. While the browser is active, retrieved resources will be stored on the computer's physical memory (RAM), and possibly also on hard drive. </p>
<p>Later, when the <em>exact</em> same resources are needed when revisiting a web page, the browser will pull those from the cache instead of the remote server. Since the cache is stored locally, in fast memory, those resources are fetched quicker, and the page loads faster.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screenshot-2020-03-06-at-12.20.39-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Speed of resource retrieval is of the essence, but so is the necessity that the resources be fresh. A stale resource is one that is out-of-date and may no longer be valid. </p>
<p>Part of the job of the browser is to identify which cached resources are stale, and refetch those that are. Since a web page typically has may resources, there will usually be a mix of stale and fresh versions in the cache.</p>
<h2 id="heading-how-does-the-browser-know-what-is-stale-in-the-cache">How does the browser know what is stale in the cache?</h2>
<p>The answer is not simple, but there are two main approaches: cache-busting and HTTP header fields.</p>
<h3 id="heading-cache-busting">cache-busting</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-188.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@sarah_elizabeth?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Sarah Shaffer / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Cache-busting is a server-side technique that ensure that the browser only fetches fresh resources. It does this indirectly. </p>
<p>While cache-busting may sound dramatic, it really doesn't bust anything, and doesn't even touch what is already cached on a browser. All cache-busting does is change the original resource's URI in a way that makes it appear to the browser that the resource is completely new. Since it looks new, it will not be in a browser's cache. The old version of the cached resource will still be cached, but eventually will wither and die, never to be accessed again.</p>
<p>Say I have a web page located at <code>www.foobar.com/about.html</code> which says everything about foobar.com that you would ever want to know. Once you visit that page, it and the resources associated with it are cached by the browser. </p>
<p>Later, foobar.com is bought out by the Quxbaz corporation, and the about page's content undergoes significant changes. The browser's cache won't have that new content, yet it may still believe the content it has is current and will never try to refetch it. </p>
<p>What do you, the Quxbaz web administrator, do to ensure all new content is pushed out?</p>
<p>Since the browser relies on the URI to find items in the cache, if the URI of a resource changes then it's like the browser has never seen it before it goes to fetch that resource from the server. </p>
<p>Thus, by changing the resource URI from <code>www.foobar.com/about.html</code> to <code>www.foobar.com/about2.html</code> (or to <code>www.quxbaz.com/about.html</code>), the browser will not find any cache resource associated with that URI, and do a full fetch from the server. The resource might be substantially the same as the original under the old URI, but the browser doesn't know that.</p>
<p>You don't have to change the page name, though. Since the URI also includes a query string by definition, you can add a version parameter to the URI: <code>www.foobar.com/about.html?v=2hef9eb1</code>. </p>
<p>In this case, the version parameter <strong>v</strong> is set new a new generated hash value whenever the content changes, or is triggered by some other process, such as a server restart. The browser sees that the query string has changed, and because query strings can affect what will be returned, it will fetch an up-to-date resource from the server.</p>
<p>Neither of these techniques will work if the old URI is directly accessed from a bookmark. Unless the browser was instructed to revalidate the URI on the last cached request (or the cached resource expired), it won't do a full fetch to refresh its cache. This brings us to the next topic.</p>
<h3 id="heading-http-header-fields">HTTP header fields</h3>
<p>Every resource request come with some meta information known as the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers">header</a>. Conversely, every response also has header information associated with it. </p>
<p>In some cases, the browser sees the response header values, and changes corresponding values in subsequent request headers. Among these header values are those that affect how resource caching is performed on the browser.</p>
<h4 id="heading-head-requests-and-conditional-requests">HEAD requests and conditional requests</h4>
<p>A <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD">HEAD request</a> is like a truncated GET or a POST request. Instead of requesting the complete resource, a HEAD request only requests the header fields that would otherwise be returned on a full request. </p>
<p>The header of a resource is generally going to be much smaller (in number of total bytes) than the resource data associated with it (the "body" of the response). The header information is sufficiently informative to allow the browser to determine the freshness of the resource in its cache.</p>
<p>HEAD requests are often used to verify the validity of a server resource (that is, does the resource still exist, and if so, has it been updated since the browser last accessed it?). The browser will use what's in its cache if the HEAD request indicates the resource is valid, otherwise it will perform a full GET or POST request and refresh its cache with what is returned.</p>
<p>With a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests">conditional request</a>, the browser sends fields in the header describing the freshness of its cached resource. This time, the server determines if the browser's cache is still fresh. </p>
<p>If it is, the server returns a 304 response with just the resource's header information, and no resource body (the data). If the browser's cache is determined to be outdated, then the server will return a full 200 OK response. </p>
<p>This mechanism is faster than using HEAD requests, since it eliminates the possibility of having to issue two requests instead of one.</p>
<p>The above simplifies what can be a pretty complicated process. There's a lot of fine-tuning involved in caching, but it all is controlled through header fields, the most important of which is <strong>cache-control.</strong></p>
<h4 id="heading-cache-control">Cache-Control</h4>
<p>When responding to a request, the server will send header fields to the browser indicating what behavior is should adapt when caching. If I load the page at <code>https://en.wikipedia.org/wiki/Uniform_Resource_Identifier</code>, the response contains this in its header record:</p>
<pre><code>cache-control: private, s-maxage=<span class="hljs-number">0</span>, max-age=<span class="hljs-number">0</span>, must-revalidate
</code></pre><p><strong>private</strong> means that only the browser should cache the document content.</p>
<p><strong>s-maxage</strong> and <strong>max-age</strong> are set to <strong>0</strong>. The <strong>s-maxage</strong> value is for proxy servers with caches, whereas <strong>max-age</strong> is intended for the browser. The effect of setting <strong>max-age</strong> <em>alone</em> is that the cached resource expires immediately, yet it may still be used (even though stale) during page reloads while in the same browser session.</p>
<p>A stale resource may be revalidation through a HEAD request, which might be followed by a GET or POST request, depending on the response. The <strong>must-revalidate</strong> directive commands the browser to revalidate the cached resource if it is stale. </p>
<p>Since <strong>max-age</strong> is set to <strong>0</strong> in this case, the cached resource is immediately stale once received. The combination of the two directives is equivalent to the single directive <strong>no-cache</strong>. </p>
<p>The two settings ensure that the browser always revalidates the cached resource, whether still in the same session or not.</p>
<p>Cache-control directives are very extensive, and at times confusing – they're a topic in their own right. A complete documented list of directives can be found <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control">here</a>.</p>
<h4 id="heading-e-tag">E-tag</h4>
<p>This is a token that the server sends and the browser retains until the next request. This is only used when the browser knows that the resource's cache lifetime has expired. </p>
<p>E-tags are server-generated hash values, which often use the resource's physical file name and last modified date on the server as a seed. When a resource file is updated, the modified date changes, and a new hash value is generated and sent in the response header to the request.</p>
<h4 id="heading-other-header-tags-affecting-caching">Other header tags affecting caching</h4>
<p>The header tags <strong>expires</strong> and <strong>last-modified</strong> are all but obsolete, yet are still sent by most servers for backward compatibility with older browsers. An example:</p>
<pre><code>expires: Thu, <span class="hljs-number">01</span> Jan <span class="hljs-number">1970</span> <span class="hljs-number">00</span>:<span class="hljs-number">00</span>:<span class="hljs-number">00</span> GMT
last-modified: Sun, <span class="hljs-number">01</span> Mar <span class="hljs-number">2020</span> <span class="hljs-number">17</span>:<span class="hljs-number">59</span>:<span class="hljs-number">02</span> GMT
</code></pre><p>Here, the expires is set to the zeroth date (historically, from the UNIX operating system). That indicates that the resource expires immediately, just as <strong>max-age=0</strong> does. Last-modified tells the browser when the latest update was made to the resource, which it can then use to decide if it should refetch it rather than use the cache value.</p>
<h2 id="heading-forcing-a-cache-refresh-from-the-browser">Forcing a cache refresh from the browser</h2>
<h3 id="heading-whats-a-hard-reload">What's a hard reload?</h3>
<p>A hard reload forces the refetch of all resources on a page, whether they're content, scripts, stylesheets or media. Pretty much everything, right? </p>
<p>Well, some resources are may not be explicitly included on a page. Instead, they can be fetched dynamically, usually after everything explicit has loaded. </p>
<p>The browser doesn't know ahead of time that this will happen, and when it does, the later requests (initiated by scripts, usually) will still use cached copies of those resources if available.</p>
<h3 id="heading-whats-clear-cache-and-hard-reload">What's clear cache and hard reload?</h3>
<p>This operation clears the entire browser cache, which has the same effect as a hard reload, but additionally causes dynamically loaded resources to be fetched as well – after all, there's nothing in the cache, so there is no choice!</p>
<h1 id="heading-content-delivery-networks-a-geo-located-cache">Content Delivery Networks: a geo-located cache</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Screenshot-2020-03-06-at-12.40.14-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>A CDN is more than just a cache, but caching is one of its jobs. A CDN stores data in geographically distributed locations so that round-trip times to and from a geographically local browser are reduced. </p>
<p>Browser requests are routed to a nearby CDN, thereby shortening the physical distance response data has to travel. CDNs also are able to handle large amounts of traffic, and provide security against some types of attacks.</p>
<p>A CDN gets its resources through an Internet Exchange Point (IXP), nodes that are part of the backbone of The Internet (in caps). There are steps to take to set up request routing to go to a CDN instead of the host server. The next step is to make sure the CDN has the current content of your website.</p>
<p>In the old days, most CDNs supported the push method: a website would push new content to a CDN hub, which would then get distributed to geographically dispersed nodes. </p>
<p>Nowadays, most CDNs use the caching protocols described above (or similar) to 1) download new resources, and 2) refresh existing ones. The browser still has its cache, and none of that changes. All a CDN does is make those transfers of new resources faster.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An In-depth Introduction to HTTP Caching: Cache-Control & Vary ]]>
                </title>
                <description>
                    <![CDATA[ Introduction - scope of the article This series of articles deals with caching in the context of HTTP. When properly done, caching can increase the performance of your application by an order of magnitude. On the contrary, when overlooked or complete... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/an-in-depth-introduction-to-http-caching-cache-control-and-vary/</link>
                <guid isPermaLink="false">66d460c5052ad259f07e4b2a</guid>
                
                    <category>
                        <![CDATA[ cache-http ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cache ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cache-control ]]>
                    </category>
                
                    <category>
                        <![CDATA[ caching ]]>
                    </category>
                
                    <category>
                        <![CDATA[ http ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Léo Jacquemin ]]>
                </dc:creator>
                <pubDate>Thu, 24 Oct 2019 09:56:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/09/martin-adams-uZZw2vh8eqY-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="heading-introduction-scope-of-the-article">Introduction - scope of the article</h3>
<p>This series of articles deals with caching in the context of HTTP. When properly done, caching can increase the performance of your application by an order of magnitude. On the contrary, when overlooked or completely ignored, it can lead to some very unwanted side effects caused by misbehaving proxy servers that, in the absence of clear caching instructions, decide to cache anyway and serve stale resources.</p>
<p>In the first part of this series, we argued that caching is the most effective way to increase performance, when measured by the page load time. In this second part, it is time to shift our focus to the mechanisms at our disposal. To put it in another way: how does HTTP caching actually work?</p>
<p>To answer this question, we decided to consider the case of an empty cache that starts progressively caching and serving resources. As it gradually receives incoming HTTP requests, our cache will start behaving accordingly. Serving the resource from the cache when a fresh copy is available, varying over multiple representations, making a conditional request... This way, we can introduce each concept progressively as we need it.</p>
<p>At first, our empty cache will have no choice but to forward requests to the origin server. This will allow us to understand how origin servers instruct our cache on what to do with the resource, such as if it is allowed to store it, and for how long. For this, we will examine each Cache-Control directive and clarify some of them that have been known to have <a target="_blank" href="https://www.google.com/search?q=must-revalidate+vs+no-cache&amp;oq=must+revalidate+vs+&amp;aqs=chrome.1.69i57j0l3.3140j0j4&amp;sourceid=chrome&amp;ie=UTF-8">conflicting meanings</a>.</p>
<p>Second, we will look at what happens when our cache receives a request for a resource it already knows. How does our cache decide if it can re-use a previously stored response? How does it map a given HTTP request to a particular resource? To answer these, we will learn about representation variations with the Vary header.</p>
<p>This article is going to focus on knowledge that’s the most valuable from a web developer’s perspective. Therefore, conditional requests are only discussed briefly and will be the focus of another article.</p>
<p>Without further ado, let us start with an overview of what we will be exploring.</p>
<h2 id="heading-the-http-caching-decision-tree">The HTTP caching decision tree</h2>
<p>Conceptually, a cache system always involve at least three participants. With HTTP, these participants are the client, the server, and the caching proxy.</p>
<p>However, when learning about HTTP caching, we strongly encourage you not to think of the client as your typical web browser because these days, they all ship with their own HTTP caching layer. It makes it difficult to clearly separate the browser from the cache. For this reason, we invite you to think of the client as a headless command line program such as cURL or any application without an embedded HTTP cache.</p>
<p>All precautions aside, let us now deep dive into the subject by taking a look at the following picture: the HTTP caching decision tree.</p>
<p><img src="https://lh5.googleusercontent.com/4wnpOGgUnR2bJxcKqsUruzDIQrdmd5o956v85GGUARZKQYG77olAVBslIc_ZL1d0FZLVwlCuLLFeUzlSBYKaE-ALN-dWjijBbkzoVDuoTVQvG_GEAGABdZDXfl8TvBw2NdAgsnxk" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This picture illustrates all the possible paths a request can take every time a client asks for a resource to an origin server behind a caching system. A careful examination of this illustration reveals that there are only four possible outcomes.</p>
<p>Clearly separating these outcomes in our minds is actually very convenient, seeing as each important caching concept (cache instructions, representation matching, conditional requests and resource aging) maps to each one of them.</p>
<p>Let us describe succinctly each one by introducing two important terms relating to the HTTP caching terminology: cache hits and cache misses.</p>
<h3 id="heading-hits-and-misses">Hits and misses</h3>
<p>The first possible outcome is when the cache finds a matching resource, and is allowed to serve it, which, in the caching world, are indeed two distinct things. This outcome is what we commonly call a cache hit, and is the reason why we use caches in the first place.</p>
<p>When a cache hit happens, it completely offloads the origin server and the latency is dramatically reduced. In fact, when the cache hit happens in the browser’s HTTP cache latency is null and the requested resource is instantly available.</p>
<p>Unfortunately, cache hits account only one of the four possible outcomes. The rest of them fall into the second category, also known as cache misses, which can happen for only three reasons.</p>
<p>The first reason a cache miss typically happens is simply when the cache does not find any matching resource in its storage. This is usually a sign that the resource has never been requested before, or has been evicted from the cache to free up some space. In such cases, the proxy has no choice but to forward the request to the origin server, fully download the response and look for caching instructions in the response headers.</p>
<p>The second reason a cache miss can happen is actually just as detrimental, where the cache detects a matching representation, one that it could potentially use. However, the resource is not considered to be <em>fresh</em> anymore - we will see how exactly in the cache-control section of this article - but is said to be <em>stale.</em></p>
<p>In such case, the cache sends a special kind of request, called a <em>conditional request</em> to the origin server. Conditional requests allow caches to retrieve resources only if they are different from the one they have in their local storage. Since only the origin server ever has the most recent representation of a given resource, conditional requests <em>always</em> have to go through the whole caching proxy chain up to the origin server.</p>
<p>These special requests have only two possible outcomes. If the resource has not changed, the cache is instructed to use its local copy by receiving a 304 Not Modified response along with updated headers and an empty body. This outcome, the third one on our list, is called a successful validation.</p>
<p>Finally, the last possible outcome is when the resource has changed. In this case, the origin server sends a normal 200 OK response, as it would if the cache was empty and had forwarded the request. To put it another way, cache misses caused by empty cache and failed validation yield exactly the same HTTP response.</p>
<p>To best visualize these four paths, it is helpful to picture them in a timeline, as illustrated below.</p>
<p><img src="https://lh6.googleusercontent.com/eV4YKvBdmE_SD0dSlu7Gt4oQKW9IpekfHv5R_odd4m4Hq4HO71cgGez9MtxtGBd5ghP36tfWoj8OTMzE-N0iWiMI5WgOusUl7dOXUtLQM7MvywGqSaYuBRbS4oH-rbXdpdwTWW6h" alt="Image" width="600" height="400" loading="lazy"></p>
<p>At first, the cache is empty. The flow of requests starts with a cache miss (empty cache outcome). On its way back, the cache would read caching instructions and store the response. All subsequent requests for this particular resource would yield to cache hits, until the resource becomes stale and needs to be revalidated.</p>
<p>Upon a first revalidation, it is possible that the resource has not changed, hence, a 304 Not Modified would be sent.</p>
<p>Then, the resource eventually gets updated by a client, typically with a PUT or a PATCH request. When the next conditional request arrives, the origin server detects that the resource has changed and replies a 200 OK with updated ETag and Last-Modified headers.</p>
<p>Knowing about cache hits and cache misses along with the 4 possible paths that every cacheable request could take, should give you a good overview of how caching works.</p>
<p>Though overviews can only get you so far. In the following section, we will give a detailed explanation of how origin servers communicate caching instructions.</p>
<h3 id="heading-how-origin-servers-communicate-caching-instructions">How origin servers communicate caching instructions</h3>
<p>Origin servers communicate their caching instructions to downstream caching proxies by adding a Cache-Control header to their response. This header is an HTTP/1.1 addition and replaces the deprecated Pragma header, that was never a standard one.</p>
<p>Cache-control header values are called directives. The specification defines a lot of them, with various uses and <a target="_blank" href="https://www.mnot.net/blog/2017/03/16/browser-caching">browser-support</a>. These directives are primarily used by developers to communicate caching instructions. However, when present in an HTTP request, clients can also influence the caching decision. Let us now take the time to describe the most useful directives.</p>
<h3 id="heading-max-age">max-age</h3>
<p>The first important Cache-Control directive to know about is the max-age directive, which allows a server to specify the lifetime of a representation. It is expressed in seconds. For instance, if a cache sees a response containing the header Cache-Control: max-age=3600, it is allowed to store and serve the same response for all subsequent requests for this resource for the next 3600 seconds.</p>
<p>During these 3600 seconds, the resource will be considered fresh and cache hits will occur. Past this delay, the resource will become stale and validation will take over.</p>
<h3 id="heading-no-store-no-cache-must-revalidate">no-store, no-cache, must-revalidate</h3>
<p>Unlike max-age, the no-store, no-cache and must-revalidate directives are about instructing caches to not cache a resource. However, they differ in subtle ways.</p>
<p>no-store is pretty self-explanatory, and in fact, it does even a little more than the name suggests. When present, a HTTP/1.1 compliant cache must not attempt to store anything, and must also take actions to delete any copy it might have, either in memory, or stored on disk.</p>
<p>The no-cache directive, on the other hand, is arguably much less self-explanatory. This directive actually means to never use a local copy without first validating with the origin server. By doing so, it prevents all possibility of a cache hit, even with fresh resources.</p>
<p>To put it another way, the no-cache directive says that caches must revalidate their representations with the origin server. But then comes another directive, awkwardly named… must-revalidate.</p>
<p>If this starts to get confusing for you, rest assured, you are not alone. If what one wants is not to cache, it has to use no-store instead of no-cache. And if what one wants is to always revalidate, it has to use no-cache instead of must-revalidate.</p>
<p>Confusing, indeed.</p>
<p>As for the must-revalidate directive, it is used to forbid a cache to serve a stale resource. If a resource is fresh, must-revalidate perfectly allows a cache to serve it without forcing any revalidation, unlike with no-store and no-cache. That’s why this header should always be used with a max-age directive, to indicate a desire to cache a resource for some time and when it’s become stale, enforce a revalidation.</p>
<p>When it comes to these last three directives, we find the choice of words to describe each of them particularly confusing: no-store and no-cache are expressed negatively whereas must-revalidate is expressed positively. Their differences would probably be more obvious if they were to be expressed in the same fashion.</p>
<p>Therefore, it is helpful to think about each of them expressed in terms of what is not allowed:</p>
<ul>
<li><p><strong>no-store:</strong> never store anything</p>
</li>
<li><p><strong>no-cache:</strong> never cache hit</p>
</li>
<li><p><strong>must-revalidate:</strong> never serve stale</p>
</li>
</ul>
<p>Technically, these directives can appear in the same Cache-Control header. It is not uncommon to see them combined as a comma-separated list of values. A lot of popular websites still seem to behave very conservatively, sending back HTML pages with the following header:</p>
<p>Cache-Control: no-cache, no-store, max-age=0, must-revalidate</p>
<p>When you stumble upon this, the intention behind it is usually pretty clear: the web development team wants to ensure that the resource never gets served stale to anyone.</p>
<p>However, such cache-buster lines are probably not necessary anymore. <a target="_blank" href="https://github.com/web-platform-tests/wpt/pull/5137">Past work</a> done in 2017 already showed that browsers are really rather compliant with the specification in respect to Cache-Control response directives. Therefore, unless you’re planning on setting up a caching stack with decades old software, you should be fine using just the directives you need. The most popular combinations will be analyzed in another article.</p>
<h3 id="heading-public-private">public, private</h3>
<p>The last important directives we haven’t discussed yet are a little bit different, as they control which types of caches are allowed to cache the resources. These are the public and private directives, private being the default one if unspecified.</p>
<p><img src="https://lh3.googleusercontent.com/kiq8Sq0igyLzRFkX4qddKF4y6xdltA1rXwjBOaqvWlqD1mJbaQe2WuLIparaOSfQ36iUT4kaHSKxzBY4TVbaVXtq7w3W6Hhq7QllsTf6WD2rAFq9MRG2AFNMI-EmUNmLn1TfmKnC" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Private caches are the ones that are supposed to be used by a single user. Typically, this is the web browser’s cache. CDN and reverse-proxies on the contrary, handle requests coming from multiple users.</p>
<p>Why do we need to distinguish these two types of caches ? The answer is straightforward: security, as illustrated by the following example.</p>
<p>Many web applications expose convenience endpoints that rely on information coming from elsewhere than the URL. If two users access their profile by requesting /users/me, at <a target="_blank" href="https://api.example/com/">https://api.example/com</a>, and their actual user id is hidden within a Authorization: Bearer 4Ja23ç42…. token, the cache won’t be able to tell these are in fact two very different resources.</p>
<p><img src="https://lh3.googleusercontent.com/48yzQ_RyKvQoWxgPmvvwijI74hSD_NNfjViTUDHeNvkmd-U-2wCqgCZWnmjRyTYNqwRGJPZJ-GuIoFbflCT_x6CCB6wIJGdHluEBK9BahnkL7pdzEmV9kwinkwJibC5JTLKAAGct" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Indeed, when constructing their cache key, caches do not inspect HTTP headers unless specifically instructed to do so, as we shall see in the next section.</p>
<h3 id="heading-s-maxage">s-maxage</h3>
<p>The s-maxage directive is like the max-age directive, except that it only applies to public caches, which are also referred to as <em>shared</em> caches (hence the s- prefix). If both directives are present, s-maxage will take precedence over max-age on public caches and be ignored on private ones.</p>
<p>When using this directive, the general rule is to always ensure that s-maxage value is below max-age’s. The reasoning behind this rule is that the closer you are to the origin, the more suitable it is to check frequently what the latest representation is.</p>
<p>Imagine you were to cache for one day in the proxy, and one hour in browsers.</p>
<p>Every time a browser would ask a resource to upstream servers, we could know <em>in</em> <em>advance</em> that the proxy will not contact the origin server for at least a day. Therefore, why not put the same TTL directly in the browsers ? As a conclusion, it is a best practice to always leave out a longer TTL in max-age than in s-maxage.</p>
<p><strong>stale-while-revalidate and stale-if-error</strong><br>These two directives are not technically part of the original specification but are part of an <a target="_blank" href="https://tools.ietf.org/html/rfc5861">extension</a> which were first described more than <a target="_blank" href="https://www.mnot.net/blog/2007/12/12/stale">10</a> years ago. Although their browser support is limited, <a target="_blank" href="https://www.fastly.com/blog/stale-while-revalidate-stale-if-error-available-today">some</a> popular CDNs have been supported them for more than 5 years!</p>
<p>Though stale-while-revalidate is pretty useful. As the name implies, it allows a cache to <em>“[...] immediately return a stale response while it revalidates it in the background, thereby hiding latency (both in the network and on the server) from clients”.</em></p>
<p>This caching extension proves really helpful for things like images, where reducing latency is critical for the user experience, and where having a stale version for a few seconds is often better than a painfully downloading image.</p>
<p>As for stale-if-error, it allows a cache to serve a stale version if the origin server returns a 5xx status code. This gives developers a chance to fix potential issues during a grace period where clients are shielded from irritating error pages.</p>
<p>Consider the case of a meteo third-party script. If the meteo server happens to be unreachable for a few minutes, it’s probably best to display a slightly outdated forecast during this lapse of time, than it is to see a portion of the page be blank (or a whole blank page if the code does not handle third-party scripts loading failures.</p>
<h3 id="heading-what-we-dont-know-yet">What we don’t know yet</h3>
<p>After examining these Cache-Control directives, we now understand how applications that are distributed on the web, tend to leverage HTTP caching mechanisms in multiple ways, depending on what they need.</p>
<p>Though what we don’t yet understand is what cache softwares actually do with the response they receive. They will most likely have to store it somewhere in order to retrieve it later. That’s the core idea of any caching system after all.</p>
<p>Under normal circumstances, this certainly looks like what we would call an implementation detail. It should be merely enough to know that resources are indeed stored some way. Yet in this case, learning just a little more is actually critical.</p>
<p>Neglecting the mechanisms that govern how caching softwares map objects from the HTTP responses space to their storage space can have really unexpected consequences, such as serving a brotli encoded Chinese document, to a user who does not understand Chinese, using a browser unable to decode brotli ¯_(ツ)_/¯</p>
<h2 id="heading-how-caches-store-and-retrieve-resources">How caches store and retrieve resources</h2>
<p>Albeit unlikely to happen, since most browsers can decode brotli - and since most people know how to 說中文 - the previous situation can still easily occur. To understand why this is the case, one must consider <em>how</em> caches store their representations.</p>
<p>By virtue of what they try to achieve, most caching softwares ought to be able to quickly retrieve simple text documents. To do so, a very simple yet powerful strategy is to use a key-value store. This strategy fits well in-memory representations. Therefore, the question one must answer when designing is the following: how to construct a cache key from an HTTP response?</p>
<p>What we are looking for here is a way to uniquely <em>identify</em> a <em>resource.</em> Conveniently, this is exactly why <a target="_blank" href="https://tools.ietf.org/html/rfc3986">URI</a>s - Uniform Resource Identifiers - were invented in the first place!</p>
<p>But URIs don’t tell the whole truth about resources. They never describe them entirely, if only for the fact that resources change over time.</p>
<p>Websites get rebranded, new content gets published and users update their profile. Granted, not for the same reasons or at the same frequency, though all resources will eventually change. In fact, the entire Conditional request specification is based on this sole observation: <em>nothing is permanent except</em> <a target="_blank" href="https://en.wikiquote.org/wiki/Heraclitus"><em>change</em></a><em>.</em></p>
<p>Philosophical quotes aside, there is, however, another time-independent reason why resources change. Indeed, any moment, resources may be available in multiple representations. This is why we have Content-Negociation.</p>
<p>The HTTP request headers Accept, Accept-Language, Accept-Encoding, Accept-Charset (and a few other headers who are not strictly speaking part of content negotiation) add another dimension on which representations can differ. As such, the problem of finding a good cache key becomes more complicated. Since all these representations share the same URI, caches must have a way to distinguish them in order to serve the right representation at each client, honoring content negotiation.</p>
<p>And since only origin servers know what different representations are available, it is again the origin server’s responsibility to indicate to a cache based on which headers it will generate a different representation. To do so, the origin servers must add a Vary <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation#The_Vary_response_header">header</a> containing the value of the request headers that cause different representations to be generated.</p>
<p>When caches see a response coming from an origin server with, for instance, the header Vary**:** Accept-Language, it will examine the value of the Accept-Language header, such as fr-FR**,** and use this value to construct a more specific cache-key, perhaps like https://example.net/home.html_<strong>fr-FR<em>.</em></strong></p>
<p>The actual implementation strategy is of little importance to us. Altering the cache key might not even be the best way to do it. It somehow has to use the <em>value</em> of the header to differentiate representations.</p>
<p>The Vary header can actually point at more than one header, when resources are available in multiple representations. Selecting a cache key when multiple headers are involved is not really much more complicated than with only one header. The real problem when varying over multiple dimensions is the combinatorial <a target="_blank" href="https://en.wikipedia.org/wiki/Combinatorial_explosion">explosion</a>.</p>
<p>Unfortunately, there are no ways around this. If you are to cache and serve your resources in multiple representations, you have to pay the cost of a large storage. If you decide to lower your vary cardinality, some of your users will receive cache hits for responses that won’t match their requests.</p>
<p>On the other hand, if you vary properly on everything, and do not have enough storage space, chances are your users won’t be seeing cache hits anytime soon.</p>
<p>Now, it is important to know that this is only a problem if you decide to use a public cache, for which two different requests coming from two different users are running the same code, at the proxy level. If you decide to leverage the browser’s cache only, then you can skip the Vary header altogether and serve resources in as many representations as you want. This is because each browser’s cache will only cache representations matching the user’s preferences. This is good news!</p>
<p>But let’s not get ahead of ourselves just yet. As we said, caches use the <em>value</em> of the header as its input to generate a more specific cache key. But what is to say that all these values are well formatted ? Absolutely nothing! This is the rather inconvenient consequence of RFC <a target="_blank" href="https://tools.ietf.org/html/rfc2468">father</a>’s <a target="_blank" href="https://en.wikipedia.org/wiki/Robustness_principle">robustness principle</a>. HTTP servers are indeed very <em>liberal in what they accept</em>.</p>
<p>However there is hope.</p>
<p>Considering the case of an origin server that can only produce a representation in two different languages, caches must be able to regroup incoming Accept-Content values such as fr, fr-FR, fr_FR_.._ into something such as FR. Otherwise, just like before with the combinatorial explosion, the number of representations will explode, but in this case, for a misguided reason.</p>
<p>The process by which all these representations are regrouped is called <em>normalization</em> and is often done at the cache. Many caches offer configuration utilities or their own languages to deal with these situations. Sometimes, the functions are even already written, or snippets can easily be found on the Internet. The following pictures illustrates the process for the infamous User-Agent header.</p>
<p><img src="https://lh3.googleusercontent.com/YjJ67y4VX8-kzzVY78G6ICtdafwsx_M6_n9ce30Qv9jVYU3LrBXQrrxb13VkPjpm9WpBNs6JParrx5VEbtuKwKr5cTSUmMiXcayum2RTwRKho3c6R5iqmYj0lYqM5f6Klb2leIAo" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Fastly, a popular CDN, <a target="_blank" href="https://www.fastly.com/blog/best-practices-using-vary-header">sampled</a> 100 000 requests and found that the Accept-Encoding header was expressed in 44 different ways ! As for the User-Agent header, they found a shy of… 8000 different ones! Without normalization, chances are that the cache will never see any hit.</p>
<p>This wraps up the section about representation variation. At this point, we know how to instruct caches to store our resources, and have learned to leverage the Vary header to prevent accidents from happening when using public caches. We have now covered enough of the specification to be able to cache resources effectively.</p>
<h3 id="heading-common-misconceptions">Common misconceptions</h3>
<p>By now, you should have a thorough understanding of how HTTP caching works. Freshness control, resource’s representations and cache hits are no longer mysterious concepts to you. And if you start to feel empowered by all this knowledge, we have some good news for you: we’ve covered a large portion of the specification, and you now know pretty much all that’s necessary to be up and running.</p>
<p>But make no mistake. Caching <em>is</em> a complex topic.</p>
<p>Experience has shown us that, unless you’re dealing with it on a day-to-day basis, what may be crystal clear today will quickly turn into something rather blurry after a few weeks. Therefore, we decided to conclude this second article by dispelling two common misconceptions that are all too easy to make.</p>
<h3 id="heading-freshness-control-and-validation">Freshness-control and validation</h3>
<p>This might seem obvious after reading the previous sections but it is worth repeating many times. Freshness control and validation (<em>which we have slightly discussed in the beginning</em>) are two very distinct mechanisms that serve two very different purposes, and involve HTTP requests between different pieces.</p>
<ul>
<li><p>Freshness control always happen in a cache <strong>and is solely based on time</strong></p>
</li>
<li><p>Validations always happen in the origin server and are based <strong>both on time and on identifiers (ETags)</strong></p>
</li>
</ul>
<p>This is something we find important to remind ourselves. It means that once the cache has received temporal instructions, it can - and best believe it will - serve resources without ever contacting the origin server until the timer expires.</p>
<p>For instance, if your web application’s HTML file reaches a browser and the HTTP response happens to include the header Cache-Control: max-age=86400 the browser will happily serve the same version of your app for a day. In this case, the browser would serve it for one day without any possible action from you or anyone, except the user, if one ever decided to flush his browser’s cache.</p>
<p>If you’re thinking everyone can make mistakes, and one day is not so bad, well, brace yourself: the maximum max-age value is… 31536000 seconds! That is to say, <em>one year.</em> This is the reason why HTML files are very dangerous to cache like this, and should generally be declared with Cache-Control: no-cache.</p>
<h3 id="heading-freshness-and-most-recent-representation">Freshness and most recent representation</h3>
<p>Another misconception is to believe that cache hits and freshness have anything to do with having the last available version of a resource. This is what we all try to achieve, but one can never truly know if the resource it has been served from a cache is indeed the most up-to-date version. In fact, this holds true even in the absence of cache. It has to do with the nature of distributed applications: other people’s actions can change the things we are interacting with at any time.</p>
<p>When querying the state of the application, the ETag header must always be used to always let the server know what our current understanding of the application’s state is. And if it does not match the server’s, 409 Conflict are expected to be received on the client side.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Along this article, we have described how caching actually works. Now would be a good time to spin up a local dev server and fiddle around with these two core headers: Cache-Control and Vary to see them in action.</p>
<p>We started by giving an overview of how caching works, illustrating the four possible paths that a request can take : the happy path (cache hit) and the 3 possible ways to have a cache miss : empty cache, failed revalidation and successful revalidation. This overview alone gives the possibility to understand how complex caching topologies can fit together.</p>
<p>Then, we went deeper and looked at all the most useful Cache-Control headers, and clarified some subtle differences that are all easily missed.</p>
<p>We also looked at the Vary header and the fundamental difference between resources and representations, to avoid serving the wrong <em>representation</em> to the right client.</p>
<p>Finally, we took some time to review it all through the angle of common misconceptions you might encounter, and hopefully helped you to avoid them.</p>
<p>In the next article, we’ll apply all of this knowledge to set up a local lab environment in which we will set an innocent node.js app on fire with a load-testing tool, right before rescuing it with the help of a popular caching software.</p>
<p>Stay tuned!</p>
<h3 id="heading-to-go-further">To go further:</h3>
<p>The official specification about the material we covered (and other things)<br><a target="_blank" href="https://tools.ietf.org/html/rfc7234#section-5.3">https://tools.ietf.org/html/rfc7234#section-5.3</a></p>
<p>Google Web’s Fundamental<br><a target="_blank" href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#defining-optimal-cache-control-policy">https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#defining-optimal-cache-control-policy</a></p>
<p>About the Cache-Control header:<br><a target="_blank" href="https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Cache-Control">https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Cache-Control</a></p>
<p>About the Vary Header:<br><a target="_blank" href="https://www.smashingmagazine.com/2017/11/understanding-vary-header/">https://www.smashingmagazine.com/2017/11/understanding-vary-header/</a><br><a target="_blank" href="https://www.fastly.com/blog/best-practices-using-vary-header">https://www.fastly.com/blog/best-practices-using-vary-header</a><br><a target="_blank" href="https://www.fastly.com/blog/getting-most-out-vary-fastly">https://www.fastly.com/blog/getting-most-out-vary-fastly</a><br><a target="_blank" href="https://www.fastly.com/blog/understanding-vary-header-browser">https://www.fastly.com/blog/understanding-vary-header-browser</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
