<?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[ Lua - 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[ Lua - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 11 May 2026 10:29:30 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/lua/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Distributed Rate Limiting System Using Redis and Lua Scripts ]]>
                </title>
                <description>
                    <![CDATA[ In this comprehensive guide, you’ll build a distributed rate limiter using Redis and Lua scripting to control user requests in a high-traffic environment. Rate limiting is crucial in any system to prevent abuse, manage traffic, and protect your resou... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-rate-limiting-system-using-redis-and-lua/</link>
                <guid isPermaLink="false">673ca31d6c7f56d7a860bbdf</guid>
                
                    <category>
                        <![CDATA[ Lua ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Birkaran Sachdev ]]>
                </dc:creator>
                <pubDate>Tue, 19 Nov 2024 14:39:25 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/CGWK6k2RduY/upload/a5ac857cec1d18720a060fc5e3462cf3.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this comprehensive guide, you’ll build a distributed rate limiter using Redis and Lua scripting to control user requests in a high-traffic environment.</p>
<p>Rate limiting is crucial in any system to prevent abuse, manage traffic, and protect your resources. By leveraging Redis and Lua, you'll build an efficient, scalable rate limiting system that can handle a large number of requests while keeping your backend services safe.</p>
<p>We will also include an interactive demo where users can simulate traffic, observe rate limits being enforced, and view logs of blocked requests.</p>
<h2 id="heading-what-you-will-learn">What You Will Learn</h2>
<ul>
<li><p>How to build a rate limiting system using Redis.</p>
</li>
<li><p>How to use Lua scripts with Redis to achieve atomic operations.</p>
</li>
<li><p>Understanding Redis data structures for efficient request tracking.</p>
</li>
<li><p>Techniques for handling high traffic in a distributed system.</p>
</li>
<li><p>Using Docker to simulate and scale a distributed rate limiter.</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before starting, ensure you have the following installed:</p>
<ul>
<li><p>Node.js (v14 or higher)</p>
</li>
<li><p>Redis</p>
</li>
<li><p>Docker (for simulating a distributed environment)</p>
</li>
<li><p>Basic understanding of Node.js, Redis, and Lua scripting.</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-you-will-learn">What You Will Learn</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-project-overview">Project Overview</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-how-to-set-up-the-project">Step 1: How to Set Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-how-to-set-up-redis">Step 2: How to Set Up Redis</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-how-to-implement-the-rate-limiter-with-redis-and-lua">Step 3: How to Implement the Rate Limiter with Redis and Lua</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-how-to-create-the-nodejs-api-server">Step 4: How to Create the Node.js API Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-how-to-test-the-rate-limiter">Step 5: How to Test the Rate Limiter</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-how-to-visualize-rate-limiting-metrics">Step 6: How to Visualize Rate Limiting Metrics</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-7-how-to-deploy-with-docker">Step 7: How to Deploy with Docker</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion-what-youve-learned">Conclusion: What You’ve Learned</a></p>
</li>
</ul>
<h2 id="heading-project-overview">Project Overview</h2>
<p>In this tutorial, you will:</p>
<ol>
<li><p>Build a rate limiter using Redis and Lua to enforce request quotas.</p>
</li>
<li><p>Use Lua scripts to ensure atomic operations, avoiding race conditions.</p>
</li>
<li><p>Implement a token bucket algorithm for rate limiting.</p>
</li>
<li><p>Create an interactive demo to simulate high traffic and visualize rate limiting in action.</p>
</li>
</ol>
<h3 id="heading-system-architecture">System Architecture</h3>
<p>You'll build the system with the following components:</p>
<ol>
<li><p><strong>API Server</strong>: Handles incoming user requests.</p>
</li>
<li><p><strong>Redis</strong>: Stores request data and enforces rate limits.</p>
</li>
<li><p><strong>Lua Scripts</strong>: Ensures atomic updates to Redis for rate limiting.</p>
</li>
<li><p><strong>Docker</strong>: Simulates a distributed environment with multiple instances.</p>
</li>
</ol>
<h2 id="heading-step-1-how-to-set-up-the-project">Step 1: How to Set Up the Project</h2>
<p>Let's start by setting up our Node.js project:</p>
<pre><code class="lang-javascript">mkdir distributed-rate-limiter
cd distributed-rate-limiter
npm init -y
</code></pre>
<p>Next, install the required dependencies:</p>
<pre><code class="lang-javascript">npm install express redis dotenv
</code></pre>
<ul>
<li><p><strong>express</strong>: A lightweight web server framework.</p>
</li>
<li><p><strong>redis</strong>: For interacting with Redis.</p>
</li>
<li><p><strong>dotenv</strong>: For managing environment variables.</p>
</li>
</ul>
<p>Create a <strong>.env</strong> file with the following content:</p>
<pre><code class="lang-javascript">REDIS_HOST=localhost
REDIS_PORT=<span class="hljs-number">6379</span>
PORT=<span class="hljs-number">3000</span>
RATE_LIMIT=<span class="hljs-number">5</span>
TIME_WINDOW=<span class="hljs-number">60</span>
</code></pre>
<p>These variables define the Redis host, port, rate limit (number of allowed requests), and the time window (in seconds).</p>
<h2 id="heading-step-2-how-to-set-up-redis">Step 2: How to Set Up Redis</h2>
<p>Before we dive into the code, ensure that Redis is installed and running on your system. If you don’t have Redis installed, you can use Docker to quickly set it up:</p>
<pre><code class="lang-javascript">docker run -p <span class="hljs-number">6379</span>:<span class="hljs-number">6379</span> --name redis-rate-limiter -d redis
</code></pre>
<h2 id="heading-step-3-how-to-implement-the-rate-limiter-with-redis-and-lua">Step 3: How to Implement the Rate Limiter with Redis and Lua</h2>
<p>To efficiently handle rate limiting, we'll use a token bucket algorithm. In this algorithm:</p>
<ol>
<li><p>Each user has a “bucket” of tokens.</p>
</li>
<li><p>Each request consumes a token.</p>
</li>
<li><p>Tokens refill periodically at a set rate.</p>
</li>
</ol>
<p>To ensure atomicity and avoid race conditions, we'll use Lua scripting with Redis. Lua scripts in Redis execute atomically, which means they can’t be interrupted by other operations while running.</p>
<h3 id="heading-how-to-create-a-lua-script-for-rate-limiting">How to Create a Lua Script for Rate Limiting</h3>
<p>Create a file called <strong>rate_limiter.lua</strong>:</p>
<pre><code class="lang-javascript">local key = KEYS[<span class="hljs-number">1</span>]
local limit = tonumber(ARGV[<span class="hljs-number">1</span>])
local <span class="hljs-built_in">window</span> = tonumber(ARGV[<span class="hljs-number">2</span>])
local current = redis.call(<span class="hljs-string">"get"</span>, key)

<span class="hljs-keyword">if</span> current and tonumber(current) &gt;= limit then
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">else</span>
    <span class="hljs-keyword">if</span> current then
        redis.call(<span class="hljs-string">"incr"</span>, key)
    <span class="hljs-keyword">else</span>
        redis.call(<span class="hljs-string">"set"</span>, key, <span class="hljs-number">1</span>, <span class="hljs-string">"EX"</span>, <span class="hljs-built_in">window</span>)
    end
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
end
</code></pre>
<ol>
<li><p><strong>Inputs</strong>:</p>
<ul>
<li><p><strong>KEYS[1]</strong>: The Redis key representing the user’s request count.</p>
</li>
<li><p><strong>ARGV[1]</strong>: The rate limit (maximum number of allowed requests).</p>
</li>
<li><p><strong>ARGV[2]</strong>: The time window (in seconds) for the rate limit.</p>
</li>
</ul>
</li>
<li><p><strong>Logic</strong>:</p>
<ul>
<li><p>If the user has reached the rate limit, return <code>0</code> (request blocked).</p>
</li>
<li><p>If the user is within the limit, increment their request count or set a new count with an expiration if it's the first request.</p>
</li>
<li><p>Return 1 (request allowed).</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-step-4-how-to-create-the-nodejs-api-server">Step 4: How to Create the Node.js API Server</h2>
<p>Create a file called <strong>server.js</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> redis = <span class="hljs-built_in">require</span>(<span class="hljs-string">'redis'</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);
<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> client = redis.createClient({
  <span class="hljs-attr">host</span>: process.env.REDIS_HOST,
  <span class="hljs-attr">port</span>: process.env.REDIS_PORT
});

<span class="hljs-keyword">const</span> rateLimitScript = fs.readFileSync(path.join(__dirname, <span class="hljs-string">'rate_limiter.lua'</span>), <span class="hljs-string">'utf8'</span>);

<span class="hljs-keyword">const</span> RATE_LIMIT = <span class="hljs-built_in">parseInt</span>(process.env.RATE_LIMIT);
<span class="hljs-keyword">const</span> TIME_WINDOW = <span class="hljs-built_in">parseInt</span>(process.env.TIME_WINDOW);

<span class="hljs-comment">// Middleware for rate limiting</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rateLimiter</span>(<span class="hljs-params">req, res, next</span>) </span>{
  <span class="hljs-keyword">const</span> ip = req.ip;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> allowed = <span class="hljs-keyword">await</span> client.eval(rateLimitScript, <span class="hljs-number">1</span>, ip, RATE_LIMIT, TIME_WINDOW);
    <span class="hljs-keyword">if</span> (allowed === <span class="hljs-number">1</span>) {
      next();
    } <span class="hljs-keyword">else</span> {
      res.status(<span class="hljs-number">429</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Too many requests. Please try again later.'</span> });
    }
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error in rate limiter:'</span>, err);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Internal server error'</span> });
  }
}

app.use(rateLimiter);

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'Welcome to the Rate Limited API!'</span>);
});

<span class="hljs-keyword">const</span> PORT = process.env.PORT;
app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<ol>
<li><p><strong>Rate Limiter Middleware</strong>:</p>
<ul>
<li><p>Retrieves the client's IP address and checks if they are within the rate limit using the Lua script.</p>
</li>
<li><p>If the user exceeds the limit, a <code>429</code> response is sent.</p>
</li>
</ul>
</li>
<li><p><strong>API Endpoint</strong>:</p>
<ul>
<li>The root endpoint is rate-limited, so users can only access it a limited number of times within the specified window.</li>
</ul>
</li>
</ol>
<h2 id="heading-step-5-how-to-test-the-rate-limiter">Step 5: How to Test the Rate Limiter</h2>
<ol>
<li><p><strong>Start Redis</strong>:</p>
<pre><code class="lang-basic"> docker start redis-rate-limiter
</code></pre>
</li>
<li><p><strong>Run the Node.js Server</strong>:</p>
<pre><code class="lang-bash"> node server.js
</code></pre>
</li>
<li><p><strong>Simulate Requests</strong>:</p>
<ul>
<li><p>Use <code>curl</code> or Postman to test the rate limiter:</p>
<pre><code class="lang-bash">  curl http://localhost:3000
</code></pre>
</li>
<li><p>Send multiple requests rapidly to see rate limiting in action.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-step-6-how-to-visualize-rate-limiting-metrics">Step 6: How to Visualize Rate Limiting Metrics</h2>
<p>To monitor rate limiting metrics like cache hits and blocked requests, we'll add logging to the middleware in <strong>server.js</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rateLimiter</span>(<span class="hljs-params">req, res, next</span>) </span>{
  <span class="hljs-keyword">const</span> ip = req.ip;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> allowed = <span class="hljs-keyword">await</span> client.eval(rateLimitScript, <span class="hljs-number">1</span>, ip, RATE_LIMIT, TIME_WINDOW);
    <span class="hljs-keyword">if</span> (allowed === <span class="hljs-number">1</span>) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Allowed request from <span class="hljs-subst">${ip}</span>`</span>);
      next();
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Blocked request from <span class="hljs-subst">${ip}</span>`</span>);
      res.status(<span class="hljs-number">429</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Too many requests. Please try again later.'</span> });
    }
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error in rate limiter:'</span>, err);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Internal server error'</span> });
  }
}
</code></pre>
<h2 id="heading-step-7-how-to-deploy-with-docker">Step 7: How to Deploy with Docker</h2>
<p>Let’s containerize the application to run it in a distributed environment.</p>
<p>Create a <code>Dockerfile</code>:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> node:<span class="hljs-number">14</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">3000</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"node"</span>, <span class="hljs-string">"server.js"</span>]</span>
</code></pre>
<p>Build and Run the Docker Container:</p>
<pre><code class="lang-bash">docker build -t rate-limiter .
docker run -p 3000:3000 rate-limiter
</code></pre>
<p>Now you can scale the rate limiter by running multiple instances.</p>
<h2 id="heading-conclusion-what-youve-learned">Conclusion: What You’ve Learned</h2>
<p>Congratulations! You’ve successfully built a distributed rate limiter using Redis and Lua scripts. Throughout this tutorial, you’ve learned how to:</p>
<ol>
<li><p>Implement rate limiting to control user requests in a distributed system.</p>
</li>
<li><p>Use Lua scripts in Redis to perform atomic operations.</p>
</li>
<li><p>Apply a token bucket algorithm to manage request quotas.</p>
</li>
<li><p>Monitor rate limiting metrics to optimize performance.</p>
</li>
<li><p>Use Docker to simulate a scalable distributed environment.</p>
</li>
</ol>
<h3 id="heading-next-steps">Next Steps:</h3>
<ol>
<li><p><strong>Add Rate Limiting by User ID</strong>: Extend the system to support rate limits per user.</p>
</li>
<li><p><strong>Integrate with Nginx</strong>: Use Nginx as a reverse proxy with Redis-backed rate limiting.</p>
</li>
<li><p><strong>Deploy with Kubernetes</strong>: Scale your rate limiter using Kubernetes for high availability.</p>
</li>
</ol>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Create Games with LÖVE 2D and Lua ]]>
                </title>
                <description>
                    <![CDATA[ The Lua programming language is becoming increasingly popular for game development. And the LÖVE 2D game engine makes it simpler to create games using Lua.  We just published a full 11-hour game development course on the freeCodeCamp.org YouTube chan... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-games-with-love-2d-and-lua/</link>
                <guid isPermaLink="false">66b201d6297cd6de0bd54606</guid>
                
                    <category>
                        <![CDATA[ love2d ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Lua ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 25 Aug 2022 13:28:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/lua.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The Lua programming language is becoming increasingly popular for game development. And the LÖVE 2D game engine makes it simpler to create games using Lua. </p>
<p>We just published a full 11-hour game development course on the freeCodeCamp.org YouTube channel that will teach you how to create games using LÖVE 2D and Lua. </p>
<p>Steve from the Steve's Teacher YouTube channel teaches this course. Steve is an experienced game developer and he has created hundreds of programming tutorials.</p>
<p>LÖVE is as framework you can use to make 2D games in Lua. It's free, open-source, and works on Windows, Mac OS X, Linux, Android and iOS.</p>
<p>In this course, you will first learn how to program in Lua. Then you will learn how to use LÖVE 2D with Lua to develop amazing games. You will create two different games during this course.</p>
<p>Here are the sections in this comprehensive course:</p>
<h3 id="heading-lua-basics">LUA BASICS</h3>
<ul>
<li>Intro to Lua</li>
<li>Installing Lua</li>
<li>Running Lua (VSCode)</li>
<li>Printing and Comments</li>
<li>Variables &amp; Data Types</li>
<li>Strings</li>
<li>Math</li>
<li>If Statements</li>
<li>Loops</li>
<li>User Input</li>
<li>Tables</li>
<li>Functions</li>
<li>Working with Files</li>
<li>Custom Modules</li>
<li>OOP</li>
</ul>
<h3 id="heading-love-2d-basics">LOVE 2D BASICS</h3>
<ul>
<li>Setup and LUD basics</li>
<li>The Config File</li>
<li>Drawing &amp; Moving Shapes</li>
<li>Keyboard Input</li>
<li>Working with Sprites</li>
</ul>
<h3 id="heading-creating-a-save-the-ball-game">CREATING A SAVE THE BALL GAME</h3>
<ul>
<li>Game Setup</li>
<li>Creating the Enemy</li>
<li>The Menu Screen</li>
<li>Adding a Point System</li>
<li>Game Over Screen</li>
</ul>
<h3 id="heading-creating-an-asteroids-game">CREATING AN ASTEROIDS GAME</h3>
<ul>
<li>Game Setup</li>
<li>The Player</li>
<li>The Thruster</li>
<li>The Game State</li>
<li>Game Text</li>
<li>Asteroids</li>
<li>Lasers</li>
<li>Laser Collision Detection</li>
<li>Player Collision Detection</li>
<li>Player Lives</li>
<li>The Menu</li>
<li>Installing &amp; Running LuaRocks</li>
<li>The Score System</li>
<li>Game Over</li>
<li>Invincible PLayer &amp; Infinite Levels</li>
<li>Game Reset &amp; High Score</li>
<li>BGM &amp; SFX</li>
</ul>
<p>Watch the full course below or on <a target="_blank" href="https://youtu.be/I549C6SmUnk">the freeCodeCamp.org YouTube channel</a> (11-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/I549C6SmUnk" 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[ A quick guide to Redis Lua scripting ]]>
                </title>
                <description>
                    <![CDATA[ By Andrei Chernikov Redis is a popular in-memory grid used for interprocess communication and data storage. You might’ve heard that it lets you run Lua scripts, but you are still not sure why. If this sounds like you, read on. Prerequisites You shou... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-quick-guide-to-redis-lua-scripting/</link>
                <guid isPermaLink="false">66d45d974a7504b7409c332e</guid>
                
                    <category>
                        <![CDATA[ Lua ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Scripting ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 25 Sep 2019 18:34:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/09/lua_script-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Andrei Chernikov</p>
<p>Redis is a popular in-memory grid used for interprocess communication and data storage. You might’ve heard that it lets you run Lua scripts, but you are still not sure why. If this sounds like you, read on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/lua_script.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You should have <a target="_blank" href="https://redis.io/topics/quickstart">Redis installed on your system</a> to follow this guide. It might be helpful to check <a target="_blank" href="https://redis.io/commands">Redis commands reference</a> while reading.</p>
<h2 id="heading-why-do-i-need-lua-scripts">Why do I need Lua Scripts?</h2>
<p>In short: performance gain. Most tasks you do in Redis involve many steps. Instead of doing these steps in the language of your application, you can do it inside Redis with Lua.</p>
<ul>
<li>This may result in better performance.</li>
<li>Also, all steps within a script are executed in an atomic way. No other Redis command can run while a script is executing.</li>
</ul>
<p>For example, I use Lua scripts to change JSON strings stored in Redis. I describe this in detail closer to the end of this article.</p>
<h2 id="heading-but-i-dont-know-any-lua">But I don’t know any Lua</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/dont-know-s.png" alt="Image" width="600" height="400" loading="lazy">
<em>A person who doesn't know any lua</em></p>
<p>Don’t worry, Lua is not very hard to understand. If you know <a target="_blank" href="https://en.wikipedia.org/wiki/List_of_C-family_programming_languages">any language of the C family</a>, you should be okay with Lua. Also, I am providing working examples in this article.</p>
<h2 id="heading-show-me-an-example">Show me an example</h2>
<p>Let’s start by running scripts via <strong>redis-cli</strong>. Start it with:</p>
<pre><code class="lang-shell">redis-cli
</code></pre>
<p>Now run the following command:</p>
<pre><code class="lang-redis">eval “redis.call(‘set’, KEYS[1], ARGV[1])” 1 key:name value
</code></pre>
<p>The <strong>EVAL</strong> command is what tells Redis to run the script which follows. The <code>”redis.call(‘set’, KEYS[1], ARGV[1])”</code>string is our script which is functionally identical to the Redis’s <code>set</code> command. Three parameters follow the script text:</p>
<ol>
<li>The number of provided keys</li>
<li>Key name</li>
<li>First argument</li>
</ol>
<p>Script arguments fall into two groups: <strong>KEYS</strong> and <strong>ARGV</strong>.</p>
<p>We specify how many keys the script requires with the number immediately following it. In our example, it is <strong>1</strong>. Immediately after this number, we need to provide these keys, one after another. They are accessible as <strong>KEYS</strong> table within the script. In our case, it contains a single value <code>key:name</code> at index <strong>1</strong>.</p>
<p><em>Note, that Lua indexed tables start with index</em> <strong><em>1,</em></strong> <em>not</em> <strong><em>0</em></strong><em>.</em></p>
<p>We can provide any number of arguments after the keys, which will be available in Lua as the <strong>ARGV</strong> table. In this example, we provide a single <strong>ARGV</strong>-argument: string <code>value</code>. As you already guessed, the above command sets the key <code>key:name</code> to value <code>value</code>.</p>
<p>It is considered a good practice to provide keys which the script uses as <strong>KEYS</strong>, and all other arguments as <strong>ARGV</strong>. So you shouldn’t specify <strong>KEYS</strong> as 0 and then provide all keys within the <strong>ARGV</strong> table.</p>
<p>Let’s now check if the script completed successfully. We are going to do this by running another script which gets the key from Redis:</p>
<p>eval “return redis.call(‘get’, KEYS[1])” 1 key:name</p>
<p>The output should be <code>”value”</code>, which means that the previous script successfully set the key <code>“key:name”</code>.</p>
<h2 id="heading-can-you-explain-the-script">Can you explain the script?</h2>
<p><img src="https://miro.medium.com/max/465/1*Utfw9sl2XFHDpyulDvoIvA.jpeg" alt="Image" width="600" height="400" loading="lazy">
<em>Doge after seeing the script above</em></p>
<p>Our first script consists of a single statement: the <code>redis.call</code> function:</p>
<pre><code class="lang-lua">redis.call(‘set’, KEYS[1], ARGV[1])
</code></pre>
<p>With<code>redis.call</code> you can execute any Redis command. The first argument is the name of this command followed by its parameters. In the case of the <code>set</code> command, these arguments are <strong>key</strong> and <strong>value</strong>. All Redis commands are supported. <a target="_blank" href="https://redis.io/commands/eval">According to the documentation</a>:</p>
<blockquote>
<p><em>Redis uses the same Lua interpreter to run all the commands</em></p>
</blockquote>
<p>Our second script does a little more than just running a single command — it also returns a value:</p>
<pre><code class="lang-redis">eval “return redis.call(‘get’, KEYS[1])” 1 key:name
</code></pre>
<p>Everything returned by the script is sent to the calling process. In our case, this process is <strong>redis-cli</strong> and you will see the result in your terminal window.</p>
<h2 id="heading-something-more-complex">Something more complex?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/man-looking-at-board.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A person planning to build a complex Redis script</em></p>
<p>I once used Lua scripts to return elements from a hash map in a particular order. The order itself was specified by hash keys stored in a sorted set.</p>
<p>Let’s first set up our data by running these commands in <strong>redis-cli</strong>:</p>
<pre><code class="lang-redis">hmset hkeys key:1 value:1 key:2 value:2 key:3 value:3 key:4 value:4 key:5 value:5 key:6 value:6
zadd order 1 key:3 2 key:1 3 key:2
</code></pre>
<p>These commands create a hash map at key <code>hkeys</code> and a sorted set at key <code>order</code> which contains selected keys from <code>hkeys</code> in a specific order.</p>
<p><em>You might want to check</em> <a target="_blank" href="https://redis.io/commands/hmset"><em>hmset</em></a> <em>and</em> <a target="_blank" href="https://redis.io/commands/zadd"><em>zadd</em></a> <em>commands reference for details.</em></p>
<p>Let’s run the following script:</p>
<pre><code class="lang-redis">eval “local order = redis.call(‘zrange’, KEYS[1], 0, -1); return redis.call(‘hmget’,KEYS[2],unpack(order));” 2 order hkeys
</code></pre>
<p>You should see the following output:</p>
<pre><code class="lang-redis">“value:3”
“value:1”
“value:2”
</code></pre>
<p>Which means that we got values of the keys we wanted and in the correct order.</p>
<h2 id="heading-do-i-have-to-specify-full-script-text-to-run-it">Do I have to specify full script text to run it?</h2>
<p>No! Redis allows you to preload a script into memory with the <strong>SCRIPT LOAD</strong> command:</p>
<pre><code class="lang-redis">script load “return redis.call(‘get’, KEYS[1])”
</code></pre>
<p>You should see an output like this:</p>
<pre><code class="lang-redis">“4e6d8fc8bb01276962cce5371fa795a7763657ae”
</code></pre>
<p>This is the unique hash of the script which you need to provide to the <strong>EVALSHA</strong> command to run the script:</p>
<pre><code class="lang-redis">evalsha 4e6d8fc8bb01276962cce5371fa795a7763657ae 1 key:name
</code></pre>
<p><em>Note: you should use actual</em> <strong><em>SHA1</em></strong> <em>hash returned by the</em> <strong><em>SCRIPT LOAD</em></strong> <em>command, the hash above is only an example.</em></p>
<h2 id="heading-what-did-you-mention-about-changing-json">What did you mention about changing JSON?</h2>
<p>Sometimes people store JSON objects in Redis. Whether it is a good idea or not is another story, but in practice, this happens a lot.</p>
<p>If you have to change a key in this JSON object, you need to get it from Redis, parse it, change the key, then serialize and set it back to Redis. There are a couple of problems with this approach:</p>
<ol>
<li>Concurrency. Another process can change this JSON between our get and set operations. In this case, the change will be lost.</li>
<li>Performance. If you do these changes often enough and if the object is rather big, this might become the bottleneck of your app. You can win some performance by implementing this logic in Lua.</li>
</ol>
<p>Let’s add a test JSON string to Redis under key <code>obj</code>:</p>
<pre><code class="lang-redis">set obj ‘{“a”:”foo”,”b”:”bar”}’
</code></pre>
<p>Now let’s run our script:</p>
<pre><code class="lang-redis">EVAL ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’ 1 obj b bar2
</code></pre>
<p>Now we will have the following object under key <code>obj</code>:</p>
<pre><code>{“a”:”foo”,”b”:”bar2<span class="hljs-string">"}</span>
</code></pre><p>You can instead load this script with the <strong>SCRIPT LOAD</strong> command:</p>
<pre><code class="lang-redis">SCRIPT LOAD ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’
</code></pre>
<p> and then run it like this:</p>
<pre><code class="lang-redis">EVALSHA &lt;your_script_sha&gt; 1 obj b bar2
</code></pre>
<p><strong>Some notes:</strong></p>
<ul>
<li>The <code>..</code> is the string concatenation operator in Lua.</li>
<li>We use a RegEx pattern to match key and replace its value. If you don’t understand this Regular Expression, <a target="_blank" href="https://medium.freecodecamp.org/simple-regex-tricks-for-beginners-3acb3fa257cb">you can check my recent guide</a>.</li>
<li>One difference of the Lua RegEx flavor from most other flavors is that we use <code>%</code> as both backreference mark and escape character for RegEx special symbols.</li>
<li>We still escape <code>”</code> with <code>\</code> and not <code>%</code> because we escape Lua string delimiter, not RegEx special symbol.</li>
</ul>
<h2 id="heading-should-i-always-use-lua-scripts">Should I always use Lua scripts?</h2>
<p>No. I recommend only using them when you can prove that it results in better performance. Always run benchmarks first.</p>
<p>If all you want is atomicity, then <a target="_blank" href="https://redis.io/topics/transactions">you should check Redis transactions instead</a>.</p>
<p>Also, your script shouldn’t be too long. Remember that while a script is running, everything else is waiting for it to finish. If your script takes quite some time, it can cause bottlenecks instead of improving performance. The script stops after reaching a timeout (5 seconds by default).</p>
<p><img src="https://miro.medium.com/max/940/1*KuCJoYrILg1eaBYHpEhQhg.jpeg" alt="Image" width="600" height="400" loading="lazy">
<em>Redis scripts should not take too much time</em></p>
<h2 id="heading-last-word">Last Word</h2>
<p>For more information on Lua check <a target="_blank" href="http://www.lua.org/start.html">lua.org</a>.</p>
<p>You can check <a target="_blank" href="https://github.com/aikei/redis-json">my node.js library on GitHub</a> for some examples of Lua scripts (see <code>src/lua</code> folder). You can also use this library in node.js to change JSON objects without writing any Lua scripts yourself.</p>
<p>— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —</p>
<p><strong>Thank you for reading this article. Questions and comments are much appreciated. You are also welcome to follow me</strong> <a target="_blank" href="https://twitter.com/aikei_en"><strong>on Twitter</strong></a><strong>.</strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Code your own Pokemon game ]]>
                </title>
                <description>
                    <![CDATA[ In this lecture from Colton Ogden, you can learn game development principles by coding a Pokemon clone in Lua. The principles you learn can apply to any programming language and any game. This lecture is part of CS50's Introduction to Game Developmen... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/code-your-own-pokemon-game/</link>
                <guid isPermaLink="false">66b20150297cd6de0bd545f1</guid>
                
                    <category>
                        <![CDATA[ cs50 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Lua ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 07 Feb 2019 19:15:37 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/ghost/2019/02/pokemon.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this lecture from Colton Ogden, you can learn game development principles by coding a Pokemon clone in Lua. The principles you learn can apply to any programming language and any game.</p>
<p>This lecture is part of CS50's Introduction to Game Development course from Harvard University. The course explores principles of 2D and 3D graphics, animation, sound, and collision detection using frameworks like Unity and LÖVE 2D, as well as languages like Lua and C#.</p>
<p>By end of the course (we're posting one lecture per day), you will have programmed several of your own games and gained a thorough understanding of the basics of game design and development.</p>
<p>This seventh lecture teaches all the key components of a Pokemon game. </p>
<p>You can watch the lecture on the <a target="_blank" href="https://www.youtube.com/watch?v=gx_qorHxBpI">freeCodeCamp.org YouTube channel</a>. (2 hour watch)</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
