<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Pulkit Goyal</title>
    <description>The latest articles on Forem by Pulkit Goyal (@pulkit110).</description>
    <link>https://forem.com/pulkit110</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F651101%2F3ee23717-efbc-4b23-bae7-304ff00fc333.png</url>
      <title>Forem: Pulkit Goyal</title>
      <link>https://forem.com/pulkit110</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pulkit110"/>
    <language>en</language>
    <item>
      <title>Managing Distributed State with GenServers in Phoenix and Elixir</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Tue, 12 Nov 2024 14:11:08 +0000</pubDate>
      <link>https://forem.com/appsignal/managing-distributed-state-with-genservers-in-phoenix-and-elixir-323a</link>
      <guid>https://forem.com/appsignal/managing-distributed-state-with-genservers-in-phoenix-and-elixir-323a</guid>
      <description>&lt;p&gt;Phoenix and Elixir are designed at their core to build real-time, fault-tolerant applications. With its elegant syntax and the robustness of the Erlang VM, Elixir is an ideal candidate for tackling the challenges of distributed state management.&lt;/p&gt;

&lt;p&gt;This two-part series will guide Phoenix/Elixir developers through the intricacies of working with Phoenix in a distributed setup.&lt;/p&gt;

&lt;p&gt;The focus of this first post will be on GenServers — the key components behind state management in distributed systems. We will explore how GenServers can be leveraged to maintain state across nodes in a Phoenix application, ensuring data consistency and fault tolerance. We’ll break down the complexities of GenServers and distributed state management into manageable and understandable segments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of Our Phoenix Application
&lt;/h2&gt;

&lt;p&gt;Let's focus on distributed state management in the context of a CRUD API. Imagine you have a popular API service built with Phoenix that handles a large number of requests from various clients. To prevent abuse and ensure fair usage, you want to implement a rate limiter that restricts the number of requests a client can make within a specific timeframe, such as 100 requests per minute.&lt;/p&gt;

&lt;p&gt;You can implement this simply using the "token bucket" strategy. In this strategy, a bucket is maintained for each client that is filled with tokens at a constant rate. Each API call consumes a single token from the bucket and is blocked if there are no tokens available.&lt;/p&gt;

&lt;p&gt;In the next section, we will set up a token bucket for a single-node scenario using a GenServer.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Single-Node Rate Limiter Implementation Using GenServer for Elixir
&lt;/h2&gt;

&lt;p&gt;GenServers are a cornerstone within the Elixir ecosystem for managing state and encapsulating functionality. They are the go-to structure for maintaining state within an application because they can hold state throughout their lifecycle and be interacted with asynchronously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;

  &lt;span class="c1"&gt;# tokens per second&lt;/span&gt;
  &lt;span class="nv"&gt;@rate&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="c1"&gt;# maximum tokens in the bucket&lt;/span&gt;
  &lt;span class="nv"&gt;@bucket_size&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;([]),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;buckets:&lt;/span&gt; &lt;span class="p"&gt;%{}}}&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;allow?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:allow?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:allow?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;current_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monotonic_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updated_bucket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;get_or_init_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;update_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;maybe_consume_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;put_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:buckets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;updated_bucket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;maybe_consume_token&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;tokens:&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;updated_bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;tokens:&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_checked:&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updated_bucket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;maybe_consume_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_current_time&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;get_or_init_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
      &lt;span class="ss"&gt;tokens:&lt;/span&gt; &lt;span class="nv"&gt;@bucket_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;last_checked:&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;update_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Add tokens based on the last time the bucket was checked&lt;/span&gt;
    &lt;span class="n"&gt;time_passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_checked&lt;/span&gt;
    &lt;span class="n"&gt;new_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time_passed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;@rate&lt;/span&gt;
    &lt;span class="n"&gt;updated_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;new_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@bucket_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;tokens:&lt;/span&gt; &lt;span class="n"&gt;updated_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_checked:&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works well in a single-node setup because the GenServer holds the token state for the entire application across web requests. We can add it to the application's supervision tree to start the API rate limiter automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;# Other Children...&lt;/span&gt;
      &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;strategy:&lt;/span&gt; &lt;span class="ss"&gt;:one_for_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first time &lt;code&gt;allow?&lt;/code&gt; is called with a new client ID, it initializes the bucket to 10 tokens, and then each &lt;code&gt;allow?&lt;/code&gt; with the same client ID consumes one token per request. Eventually, the eleventh request in the same second is rejected because there are no more tokens. If the client tries again after a while, the requests are allowed again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;_i&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allow?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"some client id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;:ok&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allow?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"some client id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But as the app scales and we deploy it across multiple nodes (e.g., in a Kubernetes cluster or across different regions), we face the challenge of coordinating rate limiting across all nodes.&lt;/p&gt;

&lt;p&gt;Each node needs to be aware of the request counts from other nodes to enforce the rate limit consistently. Without a distributed solution, each node would only track requests it directly handles, leading to inconsistent rate limiting.&lt;/p&gt;

&lt;p&gt;You might think that maintaining request limits in memory is not feasible at a scale that requires multiple nodes. But since each client's state is just a single integer for the token size and a single integer for the timestamp, this doesn't require a large amount of memory (2 * 64 bytes per client). Even if there are 100k concurrent clients, less than 15MB of in-memory state is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding GenServers in a Distributed Elixir Environment
&lt;/h2&gt;

&lt;p&gt;Distributed systems pose unique challenges, particularly when it comes to state management. Network partitions, node failures, and latency are just a few issues that can disrupt state consistency across nodes. Ensuring that all nodes have the correct state or can recover it when things go wrong is critical for a system's reliability.&lt;/p&gt;

&lt;p&gt;GenServers can be distributed across nodes in a cluster, allowing them to share state and handle requests from different parts of a system. By leveraging the built-in distribution mechanisms of the BEAM VM, GenServers can communicate across nodes with the same ease as within a single node.&lt;/p&gt;

&lt;p&gt;In the next section, we will use some strategies to support rate limiting across multiple nodes in the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Distributed GenServers Using a Single Global Process
&lt;/h2&gt;

&lt;p&gt;The simplest strategy to support a rate limiter across a whole cluster is to start a single global process that manages the limits.&lt;br&gt;
This is simple to do using Erlang's &lt;a href="https://www.erlang.org/docs/18/man/global" rel="noopener noreferrer"&gt;&lt;code&gt;:global&lt;/code&gt; name registration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the single node setup above, we register the &lt;code&gt;GenServer&lt;/code&gt; under the name &lt;code&gt;MyApp.TokenBucketRateLimiter&lt;/code&gt; (&lt;code&gt;__MODULE__&lt;/code&gt; contains the name of the current module). This registers the process locally on the node. It is also possible to register it globally using a &lt;code&gt;{:global, name}&lt;/code&gt; tuple when calling &lt;a href="https://hexdocs.pm/elixir/GenServer.html#module-name-registration" rel="noopener noreferrer"&gt;&lt;code&gt;GenServer.start_link/3&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
This registers the process under the given name globally across the whole cluster. Note that since we update the process name in &lt;code&gt;start_link&lt;/code&gt;, we also have to update it when using any &lt;code&gt;call&lt;/code&gt;, &lt;code&gt;cast&lt;/code&gt;, and friends.&lt;/p&gt;

&lt;p&gt;Let's update the code to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:global&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;allow?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:global&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:allow?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enforces that only a single process with the global name &lt;code&gt;MyApp.TokenBucketRateLimiter&lt;/code&gt; can exist across the cluster. However, this is insufficient, as it will prevent all other application nodes from joining our cluster because the supervision tree cannot start all its processes. Let's try it out by starting a few nodes in the cluster.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first node starts fine:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;   &lt;span class="err"&gt;➜&lt;/span&gt; &lt;span class="n"&gt;iex&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;node1&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="n"&gt;asdf&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;S&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt;
   &lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node1&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;But as soon as we start a second node and connect it to the cluster, the application crashes:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;   &lt;span class="err"&gt;➜&lt;/span&gt; &lt;span class="n"&gt;iex&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;node2&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="n"&gt;asdf&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;S&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt;
   &lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node2&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:"node1@127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;notice&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt; &lt;span class="n"&gt;my_app&lt;/span&gt; &lt;span class="ss"&gt;exited:&lt;/span&gt; &lt;span class="n"&gt;shutdown&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to make sure that the &lt;code&gt;start_link&lt;/code&gt; function of the rate limiter doesn't generate any errors when a process already exists on another node. To do this, we can check and modify the &lt;code&gt;start_link&lt;/code&gt; function to return &lt;code&gt;:ignore&lt;/code&gt; when the process already exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;tuple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:global&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;whereis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_pid&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:ignore&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's done, we can start multiple nodes in the cluster, and they will all ping a central rate limiter instance to allow or deny incoming requests. The central rate limiter will be the GenServer process that happens to start first, i.e., the first node in the cluster to come up.&lt;/p&gt;

&lt;p&gt;While this works, there are several issues with this approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The node is a single point of failure now. If the node goes down, the rate limiter will be unreachable until another node starts it. Even worse, this is not handled automatically, so we might be left with no rate limiter process unless a new node is started.&lt;/li&gt;
&lt;li&gt;The state is on a single node. This means that if the rate limiter process is terminated/restarted (either due to a programming error or node failure), the state is lost.&lt;/li&gt;
&lt;li&gt;All nodes in the cluster have to make a call to the single node on every API call.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Using Multiple Processes Across the Cluster
&lt;/h2&gt;

&lt;p&gt;In order to provide better fault tolerance when managing state across distributed nodes, we can use a combination of techniques, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State partitioning&lt;/strong&gt;: Dividing the state into partitions so that each GenServer instance handles a subset of the data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replication&lt;/strong&gt;: Replicating state across nodes to provide redundancy and increase fault tolerance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflict resolution&lt;/strong&gt;: Implementing strategies to handle state conflicts, such as using version vectors or CRDTs (Conflict-free Replicated Data Types).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see how we can use CRDTs to provide super-fast data access alongside eventual consistency and data replication guarantees.&lt;/p&gt;

&lt;p&gt;We will use the Elixir library &lt;a href="https://github.com/derekkraan/delta_crdt_ex" rel="noopener noreferrer"&gt;&lt;code&gt;DeltaCrdt&lt;/code&gt;&lt;/a&gt; to manage shared state across multiple nodes in the cluster.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: In addition to &lt;code&gt;DeltaCrdt&lt;/code&gt;, other libraries like &lt;a href="https://github.com/derekkraan/horde" rel="noopener noreferrer"&gt;&lt;code&gt;Horde&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/bitwalker/swarm" rel="noopener noreferrer"&gt;&lt;code&gt;Swarm&lt;/code&gt;&lt;/a&gt; can help you to coordinate processes and state across several nodes in the cluster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's add it to &lt;code&gt;mix.exs&lt;/code&gt; to get started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;MixProject&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:delta_crdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.6.3"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;DeltaCrdt&lt;/code&gt; provides a simple-to-use API for managing a map of data that is guaranteed to be conflict-free (across distributed usage) and replicated across multiple nodes. For conflict resolution, it provides &lt;a href="https://hexdocs.pm/delta_crdt/DeltaCrdt.AWLWWMap.html" rel="noopener noreferrer"&gt;&lt;code&gt;AWLWWMap&lt;/code&gt;&lt;/a&gt; (that stands for 'Add-Wins Last-Write-Wins Map) so that in the case of a conflict, the last write always wins.&lt;/p&gt;

&lt;p&gt;The API is simple — you start multiple &lt;code&gt;DeltaCrdt&lt;/code&gt; processes (which can be on the same node or multiple nodes) and create a cluster with them using &lt;a href="https://hexdocs.pm/delta_crdt/DeltaCrdt.html#set_neighbours/2" rel="noopener noreferrer"&gt;&lt;code&gt;set_neighbours/2&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crdt1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AWLWWMap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crdt2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AWLWWMap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_neighbours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crdt1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;crdt2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crdt1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;%{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once neighbours are set, adding any data to one CRDT automatically syncs with the second one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crdt1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crdt2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Starting A One Rate Limiter Per Node
&lt;/h3&gt;

&lt;p&gt;With this out of the way, we can update our implementation of the rate limiter to use &lt;code&gt;DeltaCrdt&lt;/code&gt; to sync states. First, we need to make sure all rate limiter processes are discoverable globally, but with unique names. One way to do that is to use the node name when naming the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;([]),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="n"&gt;global_tuple&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;global_tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="no"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:global&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Syncing GenServer State With CRDT
&lt;/h3&gt;

&lt;p&gt;Now that all nodes start their own copy of the rate limiter, we need to sync the state. Let's do that by starting a &lt;code&gt;DeltaCrdt&lt;/code&gt; process from the &lt;code&gt;GenServer&lt;/code&gt; and using the CRDT to make decisions about the rate limits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AWLWWMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;sync_interval:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;crdt:&lt;/span&gt; &lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;allow?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;global_tuple&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:allow?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:allow?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;current_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;os_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updated_bucket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;get_or_init_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;update_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;maybe_consume_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Update the CRDT with the new bucket state&lt;/span&gt;
    &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updated_bucket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;get_or_init_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;default_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;default_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;tokens:&lt;/span&gt; &lt;span class="nv"&gt;@bucket_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_checked:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The major changes here from the single-node approach are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instead of &lt;code&gt;Map.get&lt;/code&gt; from the local &lt;code&gt;GenServer&lt;/code&gt; state, we use &lt;code&gt;DeltaCrdt.get&lt;/code&gt; to get the key from the CRDT instead. This fetches the data from the local copy of the CRDT which is very fast to access and guarantees eventual consistency.&lt;/li&gt;
&lt;li&gt;Similar to the above, we use &lt;code&gt;DeltaCrdt.put&lt;/code&gt; to update the shared state instead of the local &lt;code&gt;GenServer&lt;/code&gt; state when updating the tokens count. This is again a fast operation that updates the local state — but with a guarantee that the changes will be eventually synced with all processes in the cluster.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Clustering the GenServers
&lt;/h3&gt;

&lt;p&gt;While we are almost there, there is one last step left. The CRDTs are currently local and do not sync with other nodes in the GenServer. We need to use the &lt;code&gt;set_neighbours/2&lt;/code&gt; API from &lt;code&gt;DeltaCRDT&lt;/code&gt; to set up a sync.&lt;/p&gt;

&lt;p&gt;Let's create a new function named &lt;code&gt;update_neighbours&lt;/code&gt; inside the GenServer that does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;update_neighbours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;neighbours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="no"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;node&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;global_tuple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;whereis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_state&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:crdt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_neighbours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;neighbours&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all we need to do is call this function when the &lt;code&gt;GenServer&lt;/code&gt; starts (from &lt;code&gt;init&lt;/code&gt; or a &lt;code&gt;handle_continue&lt;/code&gt; callback).&lt;/p&gt;

&lt;p&gt;The above piece of code takes care of updating CRDT neighbors when a new process starts. But &lt;code&gt;set_neighbours&lt;/code&gt; is a one-sided operation (i.e., it sets up &lt;code&gt;put&lt;/code&gt;s from the CRDT to its neighbors, but not the other way around). To ensure servers that have already started also update their neighbors, we must call &lt;code&gt;update_neighbours&lt;/code&gt; on all cluster processes as soon as any service starts.&lt;/p&gt;

&lt;p&gt;Let's add a new &lt;code&gt;refresh_peer_neighbours&lt;/code&gt; function to do that (which should then be called after the initialization of the &lt;code&gt;GenServer&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;refresh_peer_neighbours&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;node&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;global_tuple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;whereis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:refresh_neighbours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:refresh_neighbours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;update_neighbours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:noreply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handling Cluster Changes
&lt;/h3&gt;

&lt;p&gt;With all this in place, there is still one final piece of the puzzle. What happens when nodes are added or removed from the cluster? To update the CRDT neighborhood on cluster-level changes, we can use &lt;a href="https://www.erlang.org/doc/apps/kernel/net_kernel.html#monitor_nodes-1" rel="noopener noreferrer"&gt;&lt;code&gt;:net_kernel.monitor_nodes(true)&lt;/code&gt;&lt;/a&gt; from Erlang. This monitors the nodes and refreshes the neighbors on any &lt;code&gt;nodeup&lt;/code&gt; or &lt;code&gt;nodedown&lt;/code&gt; events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AWLWWMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;sync_interval:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Monitor for addition of new nodes&lt;/span&gt;
  &lt;span class="ss"&gt;:net_kernel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monitor_nodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;crdt:&lt;/span&gt; &lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:continue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_info&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:nodeup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_node&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="ss"&gt;:refresh_neighbours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:noreply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_info&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:nodedown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_node&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="ss"&gt;:refresh_neighbours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:noreply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This finally brings us to the end of our implementation. There are some edge cases to consider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Avoiding deadlocks when refreshing neighbours (since we need to fetch the PID of the CRDTs from all nodes).&lt;/li&gt;
&lt;li&gt;Handling cases where the &lt;code&gt;RateLimiter&lt;/code&gt; does not exist on a node (e.g., when it is being restarted).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/pulkit110/6497bd0b8e1ff78d87253bd3cb66ecb9" rel="noopener noreferrer"&gt;Here is the full implementation&lt;/a&gt;. Let's take it for a spin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Node 1&lt;/span&gt;
&lt;span class="err"&gt;➜&lt;/span&gt; &lt;span class="n"&gt;iex&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;node1&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="n"&gt;asdf&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;S&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node1&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;# Node2&lt;/span&gt;
&lt;span class="err"&gt;➜&lt;/span&gt; &lt;span class="n"&gt;iex&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;node2&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="n"&gt;asdf&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;S&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node2&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:"node1@127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node2&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allow?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"some client id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node2&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"some client id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;tokens:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_checked:&lt;/span&gt; &lt;span class="mi"&gt;1725358705&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Back on Node1&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node1&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TokenBucketRateLimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crdt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;DeltaCrdt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"some client id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;tokens:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_checked:&lt;/span&gt; &lt;span class="mi"&gt;1725358705&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it for part one of this series!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this first part of our Distributed Phoenix series, we've taken an in-depth look at how GenServers and Delta CRDTs can be leveraged to manage distributed state in a Phoenix application. We've implemented a token bucket rate limiter across multiple nodes, ensuring consistency and fault tolerance even in a distributed setup. &lt;/p&gt;

&lt;p&gt;This foundational knowledge is crucial for building scalable, resilient systems that can handle high traffic and maintain data integrity across multiple servers.&lt;/p&gt;

&lt;p&gt;In part two, we'll dive deeper into advanced techniques for optimizing distributed systems, including strategies for deploying and scaling distributed applications.&lt;/p&gt;

&lt;p&gt;Stay tuned for more insights and practical examples that will help you master the art of distributed applications with Phoenix and Elixir.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
    </item>
    <item>
      <title>LiveState for Elixir: An Overview and How to Build Embeddable Web Apps</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Tue, 03 Sep 2024 13:52:49 +0000</pubDate>
      <link>https://forem.com/appsignal/livestate-for-elixir-an-overview-and-how-to-build-embeddable-web-apps-2ncf</link>
      <guid>https://forem.com/appsignal/livestate-for-elixir-an-overview-and-how-to-build-embeddable-web-apps-2ncf</guid>
      <description>&lt;p&gt;If you have programmed with Phoenix, you already know what a delight it can be to work with LiveView. LiveView simplifies your development process by moving all state management to the server. This reduces the complexity of coordinating states between the client and server.&lt;/p&gt;

&lt;p&gt;LiveState aims to extend a LiveView-like development flow to embeddable web apps. But before we delve deeper into LiveState, let’s first understand what embeddable web apps are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embeddable Web Apps
&lt;/h2&gt;

&lt;p&gt;Embeddable web apps are applications designed to be embedded within another website. These apps are typically small and focus on a specific feature.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A comments section on a blog post&lt;/li&gt;
&lt;li&gt;A contact form on an otherwise static website&lt;/li&gt;
&lt;li&gt;A chat bubble or support widget&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LiveState brings the ease and efficiency of the LiveView workflow to the development of these embeddable web apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is LiveState for Elixir?
&lt;/h2&gt;

&lt;p&gt;LiveState is a framework that simplifies creating embeddable web applications by maintaining a server's state.&lt;/p&gt;

&lt;p&gt;This has several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralized State Management&lt;/strong&gt;: You can avoid the complexities of synchronizing state between the client and server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Updates&lt;/strong&gt;: LiveState enables real-time updates, ensuring that users always see the most current data without needing to refresh the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Client Complexity&lt;/strong&gt;: Client-side code can remain simple and lightweight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security&lt;/strong&gt;: Sensitive data is less exposed to potential security threats on the client side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we will see later in this post, building robust and dynamic embeddable web apps using LiveState is straightforward. With minimal effort, you can leverage the power and simplicity of server-side state management.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Use Cases
&lt;/h2&gt;

&lt;p&gt;In addition to embeddable web apps, LiveState excels in another important area: highly interactive client components. These components can even exist within a traditional LiveView app, where certain parts of the application are managed using LiveState alongside client-side JavaScript frameworks like React, SolidJS, or LitComponents.&lt;/p&gt;

&lt;p&gt;Within a traditional LiveView app, some sections might require more interactivity and a richer client-side experience. LiveState can manage these highly interactive parts using client-side frameworks like React, SolidJS, or LitComponents, while still leveraging the server-side state management benefits of LiveView.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Between LiveView and LiveState
&lt;/h2&gt;

&lt;p&gt;When deciding whether to use LiveView or LiveState, consider the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LiveView&lt;/strong&gt;: Best suited for applications where most of the interactivity and state management can be handled on the server. This simplifies the client-side code and leverages the power of Elixir and Phoenix to manage state and interactivity efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LiveState&lt;/strong&gt;: Ideal for scenarios requiring embeddable features or highly interactive client-side components. If parts of your app need to be embedded in other websites or require rich interactivity that benefits from JavaScript frameworks, LiveState offers a flexible and powerful solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example: Creating An Embeddable Phoenix Web App
&lt;/h2&gt;

&lt;p&gt;Let’s see how LiveState works in practice by integrating it into a Phoenix app to create an embeddable web app. We'll build a LiveState component to manage a to-do list.&lt;/p&gt;

&lt;p&gt;We'll also build a Phoenix channel backend and use LitElement for our front-end component. The front-end component will mostly be plumbing — we'll use LiveState to manage the state and events on the Phoenix backend, similar to LiveView.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Add Dependencies
&lt;/h3&gt;

&lt;p&gt;First, add the necessary dependencies to your &lt;code&gt;mix.exs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;TodoApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;MixProject&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Project&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:live_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.8.1"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:cors_plug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 3.0"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Update Your Endpoint
&lt;/h3&gt;

&lt;p&gt;Next, update your &lt;code&gt;Endpoint&lt;/code&gt; to set up a socket for the channel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;TodoAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;otp_app:&lt;/span&gt; &lt;span class="ss"&gt;:todo_app&lt;/span&gt;

  &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="s2"&gt;"/socket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;TodoAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveStateSocket&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create the &lt;code&gt;Phoenix.Socket&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Then create the &lt;code&gt;Phoenix.Socket&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;TodoAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveStateSocket&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Socket&lt;/span&gt;

  &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="s2"&gt;"todos:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;TodoAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TodosChannel&lt;/span&gt;
  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"todos:*"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a standard Phoenix Socket. If you have worked with &lt;a href="https://hexdocs.pm/phoenix/channels.html" rel="noopener noreferrer"&gt;channels&lt;/a&gt; before, you may already be familiar with how this works. For new users, the &lt;a href="https://hexdocs.pm/phoenix/Phoenix.Socket.html#channel/3" rel="noopener noreferrer"&gt;&lt;code&gt;channel&lt;/code&gt; macro&lt;/a&gt; defines a channel matching a given topic.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that we use simple implementations for the &lt;code&gt;connect&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt; callbacks that allow all connections. This keeps the guide straightforward, but in a real-world app, you would likely modify them to accept only authenticated users.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Define the Channel
&lt;/h3&gt;

&lt;p&gt;Now, let's define the channel.&lt;br&gt;
This will be the core of our backend, which will be responsible for maintaining the server-side state and handling events dispatched from the client side. It functions similarly to a &lt;code&gt;Phoenix.LiveView&lt;/code&gt; in a traditional setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;TodoAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TodosChannel&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;LiveState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;web_module:&lt;/span&gt; &lt;span class="no"&gt;TodoAppWeb&lt;/span&gt;

  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;LiveState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Event&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_socket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;todos:&lt;/span&gt; &lt;span class="n"&gt;list_todos&lt;/span&gt;&lt;span class="p"&gt;()}}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;list_todos&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Todos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list_todos&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt;&lt;span class="no"&gt;Todos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:completed&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the most basic setup for the channel. Let's break it down.&lt;/p&gt;

&lt;p&gt;A new channel is initialized as soon as a client connects to the WebSocket and subscribes to the &lt;code&gt;todos:*&lt;/code&gt; topic. In the &lt;code&gt;init&lt;/code&gt; callback, we add all existing &lt;code&gt;todos&lt;/code&gt; to the current state, making this state available to the client side.&lt;/p&gt;

&lt;p&gt;We will expand on this module later. First, let's look at the final part of our setup: the client component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build the Front-End Component with &lt;code&gt;LitElement&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;We'll use &lt;a href="https://lit.dev/" rel="noopener noreferrer"&gt;&lt;code&gt;LitElement&lt;/code&gt;&lt;/a&gt;, so navigate to the &lt;code&gt;assets&lt;/code&gt; directory and install &lt;code&gt;lit&lt;/code&gt; and &lt;code&gt;phx-live-state&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# assets&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;lit phx-live-state &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If you are new to &lt;code&gt;LitElement&lt;/code&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements" rel="noopener noreferrer"&gt;custom HTML elements&lt;/a&gt;, now is a good time to review the basic concepts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, create a new custom element to render the &lt;code&gt;todos&lt;/code&gt; inside &lt;code&gt;assets/js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// assets/js/modules/todos/TodoListElement.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;customElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lit/decorators.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LiveState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connectElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;phx-live-state&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;customElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;todo-list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoListElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;property&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;state&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;liveState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LiveState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`todos:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;connectElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;liveState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;ul style="list-style-type: none"&amp;gt;
        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
            &amp;lt;li&amp;gt;
              &amp;lt;input
                type="checkbox"
                id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="s2"&gt;`todo-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
                ?checked=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
              /&amp;gt;
              &amp;lt;label for=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="s2"&gt;`todo-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/label&amp;gt;
            &amp;lt;/li&amp;gt;
          `&lt;/span&gt;
        &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
      &amp;lt;/ul&amp;gt;
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TodoListElement&lt;/code&gt; Component&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we define a new &lt;code&gt;LitElement&lt;/code&gt; component named &lt;code&gt;TodoListElement&lt;/code&gt; using the &lt;code&gt;@customElement&lt;/code&gt; decorator. This component is responsible for fetching and displaying a list of todos.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@property&lt;/code&gt;: The &lt;code&gt;url&lt;/code&gt; property specifies the endpoint for fetching &lt;code&gt;todos&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@state&lt;/code&gt;: The &lt;code&gt;todos&lt;/code&gt; array holds the list of to-dos fetched from the server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;LiveState&lt;/code&gt; Integration&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;connectedCallback&lt;/code&gt; method, we set up &lt;code&gt;LiveState&lt;/code&gt; to synchronize our component's state with the server.&lt;/p&gt;

&lt;p&gt;LiveState is configured with the specified URL and a topic derived from the current page's URL. Using the page's URL is just an example; it can be utilized on the server side to separate to-dos based on the page the component is embedded on.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;connectElement&lt;/code&gt; function links the &lt;code&gt;todos&lt;/code&gt; state in our component with the &lt;code&gt;LiveState&lt;/code&gt; instance, ensuring real-time updates.&lt;/p&gt;

&lt;p&gt;There are additional options available with &lt;code&gt;connectElement&lt;/code&gt; that we will discuss later.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rendering the To-do List&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;render&lt;/code&gt; method generates the HTML structure for our to-do list, displaying each to-do item with a checkbox and label.&lt;/p&gt;

&lt;p&gt;Now you can include this component inside your app's JavaScript file (&lt;code&gt;assets/js/app.js&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./modules/todos/TodoListElement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will make the component available for use. Since we configured it as a custom HTML element, it's simple to use on a page. You can just use the &lt;code&gt;todo-list&lt;/code&gt; element and pass a URL (configured as a &lt;code&gt;property&lt;/code&gt;) to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;todo-list&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"ws://127.0.0.1:4000/socket"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/todo-list&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already have some to-dos, you should now start seeing them on the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding New To-dos
&lt;/h2&gt;

&lt;p&gt;Next, let's add a way to create new to-dos.&lt;/p&gt;

&lt;p&gt;First, we'll update the client to create new to-dos. Modify the &lt;code&gt;connectedCallback&lt;/code&gt; to send an &lt;code&gt;add_todo&lt;/code&gt; event and receive the &lt;code&gt;todo_created&lt;/code&gt; event from the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="nf"&gt;connectElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;liveState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add_todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo_created&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then update the &lt;code&gt;render&lt;/code&gt; method to include a form that will send the &lt;code&gt;add_todo&lt;/code&gt; event to the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;ul style="list-style-type: none"&amp;gt;
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
        &amp;lt;li&amp;gt;
          &amp;lt;input type="checkbox" id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="s2"&gt;`todo-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ?checked=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;
          &amp;lt;label for=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="s2"&gt;`todo-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/label&amp;gt;
        &amp;lt;/li&amp;gt;
      `&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
    &amp;lt;/ul&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;form @submit=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;label for="todo"&amp;gt;Todo&amp;lt;/label&amp;gt;
          &amp;lt;input id="todo" name="title" required&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;button&amp;gt;Add Todo&amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we referenced the &lt;code&gt;addTodo&lt;/code&gt; method in the form's &lt;code&gt;@submit&lt;/code&gt; callback.&lt;br&gt;
Let's add that method as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[name="title"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;titleInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add_todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;titleInput&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation is straightforward. We need to get the value of the title input and dispatch an event. The event name should match what we configured to &lt;code&gt;send&lt;/code&gt; inside the &lt;code&gt;connectElement&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;We used another directive, &lt;code&gt;@query&lt;/code&gt;, from &lt;code&gt;LitElement&lt;/code&gt; to query the &lt;code&gt;title&lt;/code&gt; input. This is a convenient method to find the element matching a selector.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-Side Handling
&lt;/h2&gt;

&lt;p&gt;On the server side, we need to handle the &lt;code&gt;add_todo&lt;/code&gt; event to create a new to-do and update the state. Let's go back to the &lt;code&gt;TodosChannel&lt;/code&gt; and add this functionality.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;TodoAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TodosChannel&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;LiveState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Event&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"add_todo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todo_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;todos:&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Todos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_todo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[%&lt;/span&gt;&lt;span class="no"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"todo_created"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;detail:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;todos:&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;]}}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LiveState&lt;/code&gt; calls the &lt;code&gt;handle_event&lt;/code&gt; callback when events are dispatched from the client. The event's &lt;code&gt;detail&lt;/code&gt; is passed from the client as the second argument to the &lt;code&gt;handle_event&lt;/code&gt; callback, while the third argument is the existing channel state, which contains the current to-dos.&lt;/p&gt;

&lt;p&gt;In our implementation, we simply create a new to-do and send a &lt;code&gt;:reply&lt;/code&gt; back to the client. If no reply is needed for certain events, you can return a &lt;code&gt;{:noreply, state}&lt;/code&gt; tuple instead.&lt;/p&gt;

&lt;p&gt;In the reply, we send a new &lt;a href="https://hexdocs.pm/live_state/LiveState.Event.html" rel="noopener noreferrer"&gt;&lt;code&gt;LiveState.Event&lt;/code&gt;&lt;/a&gt; and update the state to include the newly created to-do.&lt;/p&gt;

&lt;p&gt;When you run the example again, you will notice that you can now add new to-dos using the form, and they will appear on the list.&lt;/p&gt;

&lt;p&gt;You can add more events to toggle to-dos, but we won't go into those in this post. If you're interested, &lt;a href="https://github.com/pulkit110/live-state-todos" rel="noopener noreferrer"&gt;check out the full code sample&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bundle Embed Script
&lt;/h2&gt;

&lt;p&gt;If you have been following closely, you'll notice that we integrated a component directly into a Phoenix app. In a typical Phoenix app, there's usually no need to do this if the component is simple enough, as you can create views using LiveView.&lt;/p&gt;

&lt;p&gt;The purpose of this example was to create a script that someone can embed on any website to get access to the &lt;code&gt;&amp;lt;todo-list&amp;gt;&lt;/code&gt; element. Creating the embeddable script from here is straightforward. There are various ways to do this depending on your app's configuration. We'll walk through it using &lt;code&gt;esbuild&lt;/code&gt;, which Phoenix configures by default for new apps.&lt;/p&gt;

&lt;p&gt;First, create a new entry point for our embeddable component that only imports the &lt;code&gt;TodoListElement&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/js/modules/todos/index.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./TodoListElement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, configure &lt;code&gt;esbuild&lt;/code&gt; to generate a new JavaScript file from this entry point. Update &lt;code&gt;config/config.exs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:esbuild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;version:&lt;/span&gt; &lt;span class="s2"&gt;"0.17.11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;# this is the default entrypoint that phoenix generates&lt;/span&gt;
  &lt;span class="ss"&gt;todo_app:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;args:&lt;/span&gt;
      &lt;span class="sx"&gt;~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;cd:&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="ss"&gt;env:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"NODE_PATH"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../deps"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;# add a new config that bundles only the modules/todos/index.ts file&lt;/span&gt;
  &lt;span class="ss"&gt;todos:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;args:&lt;/span&gt;
      &lt;span class="sx"&gt;~w(js/modules/todos/index.ts --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;cd:&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="ss"&gt;env:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"NODE_PATH"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../deps"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want the embeddable JavaScript to be generated during development, update &lt;code&gt;config/dev.exs&lt;/code&gt; to add a new watcher:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:todo_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;TodoAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;# other endpoint config&lt;/span&gt;
  &lt;span class="ss"&gt;watchers:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="c1"&gt;# the default watched generated by phoenix&lt;/span&gt;
    &lt;span class="ss"&gt;esbuild:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Esbuild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:install_and_run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:todo_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sx"&gt;~w(--sourcemap=inline --watch)&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
    &lt;span class="c1"&gt;# a new watcher that just watches the todo element (matches the `todos` from config.exs)&lt;/span&gt;
    &lt;span class="ss"&gt;esbuild_todos:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Esbuild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:install_and_run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sx"&gt;~w(--sourcemap=inline --watch)&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart your server, and you should see a new JavaScript file generated inside &lt;code&gt;priv/static/assets&lt;/code&gt;. If you embed this component on an external website, include the new JS file and add the &lt;code&gt;&amp;lt;todo-element&amp;gt;&lt;/code&gt; as a regular HTML element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating With JS Frameworks
&lt;/h2&gt;

&lt;p&gt;We've seen an example of integrating &lt;code&gt;LiveState&lt;/code&gt; with &lt;code&gt;LitElement&lt;/code&gt;, but this is not a requirement. You can also use vanilla JavaScript, adding the &lt;a href="https://launchscout.github.io/phx-live-state/" rel="noopener noreferrer"&gt;phx-live-state&lt;/a&gt; package to directly dispatch and listen to events on the &lt;code&gt;LiveState&lt;/code&gt; instance without using &lt;code&gt;connectElement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To use React, the author of LiveState provides a &lt;a href="https://github.com/launchscout/use-live-state" rel="noopener noreferrer"&gt;&lt;code&gt;use-live-state&lt;/code&gt;&lt;/a&gt; hook that simplifies the integration process.&lt;/p&gt;

&lt;p&gt;Using this hook, you can efficiently manage the state and events of your to-do list within a React component. This makes it easy to synchronize the client-side state with the server in real time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TodoList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pushEvent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLiveState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;liveState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"list-style-type: none"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      $&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`todo-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;for&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`todo-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      ))}
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="si"&gt;}&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it for now!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;LiveState brings the simplicity and power of LiveView to embeddable web apps and highly interactive client components.&lt;/p&gt;

&lt;p&gt;By maintaining server state, LiveState ensures centralized state management, real-time updates, reduced client complexity, and enhanced security.&lt;/p&gt;

&lt;p&gt;It is especially useful if parts of your Elixir application need to be embedded in other websites or require rich interactivity with JavaScript frameworks.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>How to Use Flume in your Elixir Application</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Tue, 16 Apr 2024 14:33:32 +0000</pubDate>
      <link>https://forem.com/appsignal/how-to-use-flume-in-your-elixir-application-49d3</link>
      <guid>https://forem.com/appsignal/how-to-use-flume-in-your-elixir-application-49d3</guid>
      <description>&lt;p&gt;As your Elixir app grows, you might need advanced control over how and where to perform background tasks or pull them off queues to manage back pressure.&lt;/p&gt;

&lt;p&gt;In this post, you will learn how to handle background jobs with Flume, a job processing system that uses GenStage and Redis. It provides durability, back pressure, job scheduling, rate limiting, and batch processing, among other things.&lt;/p&gt;

&lt;p&gt;We will expand on each of these features in detail.&lt;/p&gt;

&lt;p&gt;But before we go further, let's quickly cover two other major libraries in the same space: Oban and Exq.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oban and Exq: Flume Alternatives for your Elixir App
&lt;/h2&gt;

&lt;p&gt;Both Oban and Exq serve as excellent alternatives to Flume.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sorentwo/oban"&gt;Oban&lt;/a&gt;, backed by PostgreSQL or SQLite, also provides a queue-based job processing system.&lt;br&gt;
&lt;a href="https://github.com/akira/exq"&gt;Exq&lt;/a&gt;, on the other hand, is backed by Redis. It provides features similar to Flume, but without built-in rate limiting and batch processing capabilities.&lt;/p&gt;

&lt;p&gt;Opt for Oban if you don't want to maintain a Redis instance to manage background jobs (Postgres typically performs adequately unless faced with queues exceeding 100k jobs or more) and do not require rate limiting.&lt;/p&gt;

&lt;p&gt;Select Exq when you need a highly efficient queuing backend for processing a substantial volume of jobs, but can forgo advanced features such as rate limiting and batch processing.&lt;/p&gt;

&lt;p&gt;If you need all three features (a queuing backend, rate limiting, and batch processing), Flume emerges as the ideal choice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A small word of warning&lt;/em&gt;: If you have experience with Rails, you are likely familiar with Sidekiq, Resque, and Delayed Job for background job processing. But note that Elixir/Erlang already has excellent alternatives built into the language in the form of &lt;a href="https://hexdocs.pm/elixir/1.16.0/GenServer.html"&gt;GenServer&lt;/a&gt;, &lt;a href="https://hexdocs.pm/elixir/1.16.0/Task.html"&gt;Task&lt;/a&gt;, and &lt;a href="https://hexdocs.pm/elixir/1.16.0/Supervisor.html"&gt;Supervisor&lt;/a&gt;, and an additional background job processing system that adds more infrastructure costs and complexity &lt;strong&gt;might not&lt;/strong&gt; be necessary.&lt;/p&gt;

&lt;p&gt;A background job processing system like Flume becomes crucial when you need to manage numerous background tasks, track their progress/status (or at least automatically retry them on failure), or apply common constraints (like queue, priority, or rate limit) to many similar jobs.&lt;/p&gt;

&lt;p&gt;Keeping all of that in mind, let's set up Flume for our Elixir app.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation and Setting Up
&lt;/h2&gt;

&lt;p&gt;To install Flume in your app, simply add the dependency in your &lt;code&gt;mix.exs&lt;/code&gt; file and run &lt;code&gt;mix deps.get&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;github:&lt;/span&gt; &lt;span class="s2"&gt;"scripbox/flume"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add Flume to your application’s supervision tree by modifying your &lt;code&gt;application.ex&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;

  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Spec&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
      &lt;span class="c1"&gt;# Start Flume supervisor&lt;/span&gt;
      &lt;span class="n"&gt;supervisor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]),&lt;/span&gt;
      &lt;span class="c1"&gt;#...&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;strategy:&lt;/span&gt; &lt;span class="ss"&gt;:one_for_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, configure it inside &lt;code&gt;config/config.exs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="no"&gt;Flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;# Redis config&lt;/span&gt;
  &lt;span class="ss"&gt;host:&lt;/span&gt; &lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="s2"&gt;"6379"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;namespace:&lt;/span&gt; &lt;span class="s2"&gt;"my-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;database:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;redis_pool_size:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are some other configuration options as well, but we will get to them later in the post. For now, this is all you need to get things set up and start creating background jobs.&lt;br&gt;
Let's create one now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;OrdersWorker&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# process the order&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To initiate a job, we execute &lt;code&gt;Flume.enqueue/4&lt;/code&gt;, specifying a queue name, a module name, a function within that module, and an array of arguments to invoke that function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Flume&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;OrdersWorker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:process&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes care of serializing the arguments and adds the job to Redis. To actually run the job, we need to define a pipeline that picks off the jobs from Redis. We'll see how to do that in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipelines in Flume for Elixir
&lt;/h2&gt;

&lt;p&gt;Pipelines define when and how the actual job processing happens in Flume. We can define pipelines in &lt;code&gt;config/config.exs&lt;/code&gt; when configuring Flume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;pipelines:&lt;/span&gt; &lt;span class="p"&gt;[%{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"default_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This directs Flume to commence processing jobs from the queue named &lt;code&gt;default&lt;/code&gt;, with a maximum of &lt;code&gt;500&lt;/code&gt; jobs (by default) running simultaneously. Consequently, Flume will initiate up to 500 concurrent processes/tasks, each executing a single job. The &lt;code&gt;max_demand&lt;/code&gt; parameter regulates this behavior. If your jobs are inherently resource-intensive, you can specify a lower number to constrain the quantity of workers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;pipelines:&lt;/span&gt; &lt;span class="p"&gt;[%{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"default_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;max_demand:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the &lt;code&gt;queue&lt;/code&gt;, there are more configuration options for advanced pipeline control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rate Limiting
&lt;/h3&gt;

&lt;p&gt;We can specify rate limits for a pipeline by configuring it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;pipelines:&lt;/span&gt; &lt;span class="p"&gt;[%{&lt;/span&gt;
  &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"default_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;rate_limit_count:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;rate_limit_scale:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will ensure that the default pipeline processes at most 100 jobs (rate limit count) per minute (rate limit scale of &lt;code&gt;60 * 1000&lt;/code&gt; milliseconds). It is also possible to share the same rate limit across multiple pipelines by specifying the optional &lt;code&gt;rate_limit_key&lt;/code&gt; when defining the pipeline.&lt;/p&gt;

&lt;p&gt;For example, if you have two pipelines that process notifications using the same rate-limited API, you can share the limit across both of them like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;pipelines:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;%{&lt;/span&gt;
    &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"email_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;rate_limit_count:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;rate_limit_scale:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
    &lt;span class="ss"&gt;rate_limit_key:&lt;/span&gt; &lt;span class="s2"&gt;"notifications"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;%{&lt;/span&gt;
    &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"sms_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"sms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;rate_limit_count:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;rate_limit_scale:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
    &lt;span class="ss"&gt;rate_limit_key:&lt;/span&gt; &lt;span class="s2"&gt;"notifications"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, both of these pipelines will process a total of (at most) 100 jobs per minute.&lt;/p&gt;

&lt;p&gt;Don't confuse this with the &lt;code&gt;max_demand&lt;/code&gt; parameter, which governs how many "concurrent" jobs can execute simultaneously.&lt;br&gt;
Even with a low max demand, it's entirely possible to rapidly process too many jobs if they tend to be short-lived. Rate limiting operates on a time scale level to ensure that the number of executions does not surpass a specified limit within a given time interval.&lt;/p&gt;
&lt;h3&gt;
  
  
  Batching
&lt;/h3&gt;

&lt;p&gt;It's also useful to define a batch size with a pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;pipelines:&lt;/span&gt; &lt;span class="p"&gt;[%{&lt;/span&gt;
  &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"default_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;max_demand:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;batch_size:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will instruct Flume to send up to 5 jobs to the same worker (and start up to 10 workers at the same time).&lt;/p&gt;

&lt;p&gt;When using batching, each worker will receive an array of all arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;OrdersWorker&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# jobs contains up to 5 arrays containing arguments for each individual call:&lt;/span&gt;
    &lt;span class="c1"&gt;# [[order1_id], [order2_id], [order3_id], [order4_id], [order5_id]]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application code determines how to manage these jobs.&lt;br&gt;
For instance, in the case of a mailer job, the &lt;code&gt;process/1&lt;/code&gt; function could utilize a bulk email API to send emails to multiple recipients in a single call, rather than making five separate calls to a standard API.&lt;/p&gt;
&lt;h3&gt;
  
  
  Runtime Control
&lt;/h3&gt;

&lt;p&gt;It is also possible to pause pipelines at runtime using &lt;code&gt;Flume.pause_all/1&lt;/code&gt; or &lt;code&gt;Flume.pause/2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To pause all pipelines permanently (across all running nodes), run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Flume&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pause_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;temporary:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;async:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you only want to pause a single pipeline, use &lt;code&gt;Flume.pause&lt;/code&gt; with the pipeline's name. It accepts the same options as &lt;code&gt;pause_all&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Flume&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"default_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;temporary:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;async:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also possible to pause a pipeline/all pipelines on a single node instead of on all nodes. This can be controlled using the temporary parameter. So, to pause a pipeline on only the current node, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Flume&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"default_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;temporary:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;async:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to &lt;code&gt;pause&lt;/code&gt; and &lt;code&gt;pause_all&lt;/code&gt;, you can run &lt;code&gt;resume&lt;/code&gt; or &lt;code&gt;resume_all&lt;/code&gt; to restart the pipelines.&lt;/p&gt;

&lt;p&gt;Pausing a pipeline can be advantageous in scenarios where you need to temporarily suspend job processing to address issues or perform maintenance tasks. For example, during system upgrades or when debugging critical issues, pausing a pipeline can prevent new jobs from being processed, thereby enabling you to stabilize the system.&lt;/p&gt;

&lt;p&gt;Another useful scenario is to manage known service downtimes.&lt;br&gt;
For instance, if your job depends on an external service that is known to be unavailable, you can pause the pipeline until the service resumes normal operation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Advanced Features in Flume
&lt;/h2&gt;

&lt;p&gt;Flume comes with an exponential back-off for failed jobs (jobs that raise an exception) by default. The default configuration is set to retry a failed job with exponential back-offs starting at 500 milliseconds with a maximum back-off of 10 seconds. A job is retried at most 5 times. This can be controlled using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;backoff_initial:&lt;/span&gt; &lt;span class="mi"&gt;30_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;backoff_max:&lt;/span&gt; &lt;span class="mi"&gt;36_00_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;max_retries:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are several other configuration options to fine-tune Flume further. Please refer to the &lt;a href="https://github.com/scripbox/flume?tab=readme-ov-file#usage"&gt;Flume guide&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;Flume uses &lt;code&gt;:telemetry&lt;/code&gt; to emit events/metrics.&lt;br&gt;
By default, the emitted events are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;[:pipeline_name, :worker, :job]&lt;/code&gt; event with the &lt;code&gt;duration&lt;/code&gt; (in milliseconds) representing the time taken to execute the job.
This is the time that your &lt;code&gt;Worker.perform&lt;/code&gt; function takes.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;[:pipeline_name, :worker]&lt;/code&gt; event with the &lt;code&gt;duration&lt;/code&gt; (in milliseconds) representing the time taken to run the job.
This includes the total time taken to decode the event payload and execute the job.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;[:queue_name, :enqueue]&lt;/code&gt; event with the serialized job's &lt;code&gt;payload_size&lt;/code&gt; (in bytes).&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;[:queue_name, :dequeue]&lt;/code&gt; event with the &lt;code&gt;count&lt;/code&gt; (number of jobs fetched), &lt;code&gt;latency&lt;/code&gt; (in milliseconds — time taken to fetch the jobs from Redis), and &lt;code&gt;payload_size&lt;/code&gt; (in bytes) after Flume fetches jobs from Redis.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are already using AppSignal, you can use something like &lt;a href="https://hexdocs.pm/telemetry_metrics_appsignal/TelemetryMetricsAppsignal.html"&gt;TelemetryMetricsAppsignal&lt;/a&gt; to collect these metrics, report them to AppSignal, and get custom dashboards.&lt;/p&gt;
&lt;h2&gt;
  
  
  Running Flume On Production
&lt;/h2&gt;

&lt;p&gt;All the usage examples we have seen up to now run Flume on the same server as the web server. While this is good for a development workflow or small production workloads, you might consider moving workers to a separate node for scalability. This can be achieved by configuring Flume pipelines based on environment variables.&lt;/p&gt;

&lt;p&gt;To control this, we can create a module that helps parse the environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;FlumeConfigurator&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@default_pipelines&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
    &lt;span class="s2"&gt;"default_pipeline"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"default_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s2"&gt;"notifications_pipeline"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
      &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"notifications_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"notifications"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;rate_limit_count:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;rate_limit_scale:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s2"&gt;"video_transcoding_pipeline"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"video_transcoding_pipeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;queue:&lt;/span&gt; &lt;span class="s2"&gt;"video_transcoding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;max_demand:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;flume_pipelines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;pipelines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"FLUME_PIPELINES"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;pipelines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;pipelines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;","&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;trim:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@default_pipelines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then configure Flume pipelines inside &lt;code&gt;runtime.exs&lt;/code&gt;/&lt;code&gt;release.exs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;FlumeConfigurator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;flume_pipelines:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:flume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;pipelines:&lt;/span&gt; &lt;span class="n"&gt;flume_pipelines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That way, if you start your released application without defining &lt;code&gt;FLUME_PIPELINES&lt;/code&gt;, Flume will not start any pipelines, but you can still enqueue jobs from your application. Then you can start other workers with &lt;code&gt;FLUME_PIPELINES&lt;/code&gt; so that all pipelines kick in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;FLUME_PIPELINES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default_pipeline,notifications_pipeline,video_transcoding_pipeline /path/to/release start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might want to stop the web server on worker-only nodes: you can control that from the &lt;code&gt;runtime.exs&lt;/code&gt;/&lt;code&gt;release.exs&lt;/code&gt; file with an environment variable.&lt;/p&gt;

&lt;p&gt;Note that this is automatically generated if you use the &lt;a href="https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Release.html"&gt;&lt;code&gt;mix phx.gen.release&lt;/code&gt;&lt;/a&gt; task to prepare your Phoenix app for release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PHX_SERVER"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:pug_n_play_platform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PugNPlayPlatformWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;server:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;When enqueueing background jobs with Flume, all the job arguments are serialized and deserialized, and all the job data needs to make a round trip to the Redis server. This means that it is important to keep the payload of the jobs as low as possible. For example, if you have something that persists in a database, instead of passing the full struct, just pass the ID and retrieve it from the database when performing the job.&lt;/p&gt;

&lt;p&gt;Another important thing to keep in mind when running jobs is that they should be idempotent. Jobs can run multiple times in cases of failure, so ensure that a job that runs twice doesn't unnecessarily affect your application or its data (or disable retries).&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In summary, Flume brings efficiency to background job processing in Elixir applications. Its easy installation, configurable pipelines, and advanced features like rate limiting and telemetry make it a valuable tool for scalable and fault-tolerant systems. Embracing best practices, such as minimizing payload and ensuring idempotency, enhances the effectiveness of your background jobs.&lt;/p&gt;

&lt;p&gt;With Flume, you not only leverage Elixir's concurrency and fault tolerance but also gain a powerful ally for managing and optimizing your application's background tasks.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>Keep Your Ruby Code Maintainable with Money-Rails</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Wed, 13 Dec 2023 15:43:52 +0000</pubDate>
      <link>https://forem.com/appsignal/keep-your-ruby-code-maintainable-with-money-rails-1a0o</link>
      <guid>https://forem.com/appsignal/keep-your-ruby-code-maintainable-with-money-rails-1a0o</guid>
      <description>&lt;p&gt;When working with money in an application, ensuring everything is accounted for is important.&lt;/p&gt;

&lt;p&gt;In this post, we will explore some common methods and best practices of handling money in your Ruby app, and see how you can use &lt;code&gt;money-rails&lt;/code&gt; to write maintainable money-handling code.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases for Storing Money
&lt;/h2&gt;

&lt;p&gt;There are several use cases where your Ruby app might need to handle money — for example, an e-commerce company that sells products, a SaaS maintaining users' subscriptions, etc.&lt;/p&gt;

&lt;p&gt;In this post, we will walk through some examples of how to handle money in an e-commerce app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing Money in a Ruby Database
&lt;/h2&gt;

&lt;p&gt;First, let’s start with strategies for storing money in your database: using a float column, the &lt;code&gt;numeric&lt;/code&gt; type, and the &lt;code&gt;integer&lt;/code&gt; type.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a Float Column
&lt;/h3&gt;

&lt;p&gt;The most obvious way to store money is to use a float column. However, because of the way floating-point numbers are stored, they do not guarantee exactness. Instead, they only approximate the actual value. While this might be sufficient for some applications, there are much better ways to store money.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the &lt;code&gt;numeric&lt;/code&gt; Type
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL"&gt;&lt;code&gt;numeric&lt;/code&gt; type&lt;/a&gt; can store arbitrary-precision numbers in a database.&lt;/p&gt;

&lt;p&gt;A numeric column can store a large range of numbers (up to 131,072 &lt;strong&gt;digits&lt;/strong&gt; before a decimal point and up to 16,383 digits after a decimal point) and is therefore perfectly suited to work with money.&lt;/p&gt;

&lt;p&gt;But one important point to note here is that calculations on numeric types are very slow compared to integer/floating-point numbers.&lt;/p&gt;

&lt;p&gt;Numeric types should be the go-to data type when you need arbitrary-precision numbers, but, depending on business logic, they are rarely needed unless it's for very specific use cases. Let’s see if we can do better in an e-commerce scenario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the &lt;code&gt;integer&lt;/code&gt; Type
&lt;/h3&gt;

&lt;p&gt;We need to store the prices of products, with the lowest unit being cents. A product can be priced at &lt;code&gt;$19.99&lt;/code&gt; but never &lt;code&gt;$19.9954321&lt;/code&gt;. This means that, instead of working at the dollar level, we will always have an integer value as the price at the cents level. We can easily store an integer without any approximation in the database using one of the integer types (e.g., &lt;code&gt;smallint&lt;/code&gt;, &lt;code&gt;integer&lt;/code&gt;, &lt;code&gt;bigint&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;But please note that this does constrain the represented values (as compared to the &lt;code&gt;numeric&lt;/code&gt; type) — the maximum &lt;code&gt;integer&lt;/code&gt; value on Postgres &lt;code&gt;2147483647&lt;/code&gt; will be &lt;code&gt;$21,474,836.47&lt;/code&gt;. This should normally be enough for any e-commerce product, but it’s good to know that there’s a limit. If you require higher precision (for example, a 10th of a cent), this is possible by just storing the amount as a mill instead of cents. Keep in mind that this will further decrease the range of values that can be represented in an integer column.&lt;/p&gt;

&lt;p&gt;But an &lt;code&gt;integer&lt;/code&gt;'s big advantage over a &lt;code&gt;numeric&lt;/code&gt; type is that calculations are very fast. As long as you can work within the integer (or &lt;code&gt;bigint&lt;/code&gt;) range and have clear constraints set, using an &lt;code&gt;integer&lt;/code&gt;/&lt;code&gt;bigint&lt;/code&gt; is the recommended storage option.&lt;/p&gt;

&lt;p&gt;Sorting out storage is just the first step to representing money in our Ruby application, though. You might also need to handle different currencies, formatting the values based on the location of users (e.g., USD is formatted as &lt;code&gt;$1,234.56&lt;/code&gt;, whereas the same amount in Euros is formatted as &lt;code&gt;€1.234,56&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;While it is possible to implement this manually, a gem like &lt;code&gt;money-rails&lt;/code&gt; can handle it out of the box for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter &lt;code&gt;money-rails&lt;/code&gt; for Ruby on Rails
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/RubyMoney/money-rails"&gt;Money-Rails&lt;/a&gt; integrates the &lt;code&gt;money&lt;/code&gt; gem in Rails. It can handle automatic conversion between the database representation of money to &lt;code&gt;Money&lt;/code&gt; instances. These instances can then be used to access all helpers available from the &lt;code&gt;money&lt;/code&gt; gem (we will get to an overview of those helpers later in this post).&lt;/p&gt;

&lt;p&gt;Additionally, &lt;code&gt;money-rails&lt;/code&gt; also has helpers for migrations and configurable validation options. Let’s start by creating a product with a price. We'll use the &lt;a href="https://github.com/RubyMoney/money-rails#migration-helpers"&gt;monetize&lt;/a&gt; helper to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# db/migrate/20230803062226_create_products.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateProducts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
    &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;monetize&lt;/span&gt; &lt;span class="ss"&gt;:price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;

      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamps&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;t.monetize :price&lt;/code&gt; adds &lt;code&gt;price_cents&lt;/code&gt; and &lt;code&gt;price_currency&lt;/code&gt; columns to the table. In addition to this, we need to mark the &lt;code&gt;price_cents&lt;/code&gt; column that &lt;code&gt;money-rails&lt;/code&gt; will control in the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/product.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;monetize&lt;/span&gt; &lt;span class="ss"&gt;:price_cents&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With just a few lines, we now have access to a lot of helpers.&lt;br&gt;
We can create a new product by simply passing a price attribute. The &lt;code&gt;price&lt;/code&gt; will automatically be converted to a cent value for the database. When accessing the &lt;code&gt;price&lt;/code&gt; later, we will have instances of &lt;code&gt;Money&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="mf"&gt;19.99&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Product:0x0000000108ff9e30 id: nil, title: "Foo", price_cents: 1999, price_currency: "USD", created_at: nil, updated_at: nil&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Money fractional:1999 currency:USD&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also pass the attributes directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;1999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Product:0x0000000108ff2130 id: nil, title: "Foo", price_cents: 1999, price_currency: "EUR", created_at: nil, updated_at: nil&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "€19,99"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Currency in the &lt;code&gt;money&lt;/code&gt; Gem for Ruby
&lt;/h2&gt;

&lt;p&gt;Currencies are consistently represented as instances of &lt;code&gt;Money::Currency&lt;/code&gt;. This not only includes the name of the currency, but a lot of additional information like the name, symbol, iso code, etc.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;042&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currency&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Money::Currency id: usd, priority: 1, symbol_first: true, thousands_separator: ,, html_entity: $, decimal_mark: ., name: United States Dollar, symbol: $, subunit_to_unit: 100, exponent: 2, iso_code: USD, iso_numeric: 840, subunit: Cent, smallest_denomination: 1, format: &amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the &lt;a href="https://github.com/RubyMoney/money/tree/main#currency"&gt;&lt;code&gt;money&lt;/code&gt; gem's currency documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's say you only have a single currency in your application and don’t need to track currency inside your database. First, set a default currency for &lt;code&gt;money&lt;/code&gt; in an initializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/initializers/money.rb&lt;/span&gt;
&lt;span class="no"&gt;MoneyRails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# set the default currency&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_currency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:usd&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the migration, disable the currency column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# db/migrate/20230803062226_create_products.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateProducts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
    &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;monetize&lt;/span&gt; &lt;span class="ss"&gt;:price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;currency: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;present: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamps&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many &lt;a href="https://github.com/RubyMoney/money-rails#migration-helpers"&gt;other Money-Rails migration helpers&lt;/a&gt; that allow null values for amounts or configure default amounts/currencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validations with &lt;code&gt;monetize&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;You can configure validations on money using the &lt;code&gt;monetize&lt;/code&gt; Active Record helper. To do this, update your model to opt in for validations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;monetize&lt;/span&gt; &lt;span class="ss"&gt;:price_cents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;numericality: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="ss"&gt;greater_than_or_equal_to: &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="ss"&gt;less_than_or_equal_to: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you try to save a product with an invalid price, validation will fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; raise_validation_error: Validation failed: Price must be greater than or equal to 0 (ActiveRecord::RecordInvalid)&lt;/span&gt;

&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;ActiveModel::Errors [#&amp;lt;ActiveModel::Error attribute=price, type=greater_than_or_equal_to, options={:allow_nil=&amp;gt;nil, :value=&amp;gt;-10, :count=&amp;gt;0}&amp;gt;]&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Localization
&lt;/h2&gt;

&lt;p&gt;Money can be configured to either use the location information provided by &lt;code&gt;i18n&lt;/code&gt; or to localize based on the amount’s currency. Use the &lt;code&gt;locale_backend&lt;/code&gt; to configure this — usually in an initializer like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/initializers/money.rb&lt;/span&gt;
&lt;span class="no"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locale_backend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:currency&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we set it to &lt;code&gt;:currency&lt;/code&gt;. This uses the formatting rules defined for each currency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;15_999_00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "$15,999.00"&lt;/span&gt;

&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price_currency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"EUR"&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "€15.999,00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To configure a consistently formatted amount regardless of the amount’s currency, use the &lt;code&gt;:i18n&lt;/code&gt; locale backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locale_backend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:i18n&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;I18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:en&lt;/span&gt;

&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;15_999_00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "$15,999.00"&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;15_999_00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "€15,999.00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using the locale backend &lt;code&gt;i18n&lt;/code&gt;, it is also possible to configure the formatting using the translation files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/locale/en.yml&lt;/span&gt;
&lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;delimiter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,"&lt;/span&gt;
        &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%u%n"&lt;/span&gt;
        &lt;span class="na"&gt;precision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
        &lt;span class="na"&gt;separator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
        &lt;span class="na"&gt;significant&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;strip_insignificant_zeros&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that if you are using &lt;a href="https://github.com/svenfuchs/rails-i18n/"&gt;&lt;code&gt;rails-i18n&lt;/code&gt;&lt;/a&gt;, configuration is automatically available for many locales.&lt;/p&gt;

&lt;h2&gt;
  
  
  Computations
&lt;/h2&gt;

&lt;p&gt;Money instances are usable as regular numerical values with all operators, so you can compare values and perform arithmetic operations (using &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;). This makes it much more intuitive to perform operations on objects containing money.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Comparisons - both value and currency must be equal for equality&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since mathematical operators work as expected, you can easily compute sum/average or price discounts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Compute invoice total by summing all line item amounts&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;LineItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;amount_cents: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;amount_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;LineItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;amount_cents: &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;amount_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;amount&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Money fractional:750 currency:USD&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;# Find the average price of a product&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Money fractional:1000 currency:USD&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to access the underlying value from a Money instance, you can do that using &lt;code&gt;amount&lt;/code&gt; or &lt;code&gt;cents&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;amount&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; BigDecimal(10)&lt;/span&gt;

&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cents&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; 1000 (Integer)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Currency Exchange
&lt;/h2&gt;

&lt;p&gt;If you are working with multiple currencies, you can automatically convert two different currencies based on exchange rates using exchange rate stores.&lt;/p&gt;

&lt;p&gt;The default implementation is just an in-memory store. It stores the exchange rates you provide using &lt;code&gt;Money.add_rate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To use it, first add a rate. Then, you can use the &lt;code&gt;exchange_to&lt;/code&gt; method to convert a money object to another currency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.92&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exchange_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Money fractional:920 currency:EUR&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a conversion rate is not present, it raises a &lt;code&gt;Money::Bank::UnknownRate&lt;/code&gt; exception.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exchange_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; No conversion rate known for 'USD' -&amp;gt; 'INR' (Money::Bank::UnknownRate)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, if you are using this in production, you must provide the exchange rate before you perform any conversions.&lt;/p&gt;

&lt;p&gt;You can provide a custom &lt;a href="https://github.com/RubyMoney/money/tree/main#exchange-rate-stores"&gt;exchange rate store&lt;/a&gt; to handle this automatically. There are also some exchange rate implementations already available as gems.&lt;br&gt;
For example, you can drop in the &lt;a href="https://github.com/RubyMoney/eu_central_bank"&gt;&lt;code&gt;eu_central_bank&lt;/code&gt;&lt;/a&gt; exchange rate store to fetch the latest exchange rates from the European Central Bank.&lt;/p&gt;

&lt;p&gt;Once the gem is installed, you can set it as the default bank in the initializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/initializers/money.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'eu_central_bank'&lt;/span&gt;
&lt;span class="n"&gt;eu_bank&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EuCentralBank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="no"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_bank&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eu_bank&lt;/span&gt;

&lt;span class="c1"&gt;# Update rates from the EU Central Bank&lt;/span&gt;
&lt;span class="c1"&gt;# Ideally this should be performed periodically in a cron job.&lt;/span&gt;
&lt;span class="c1"&gt;# If you need conversions rarely, you can call it before using exchange_to.&lt;/span&gt;
&lt;span class="n"&gt;eu_bank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_rates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once set up, you can simply exchange any currency, and it should work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;price_cents: &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price_currency: &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exchange_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; Money.from_cents(92, "EUR")&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;In this post, we saw how to store and work with money in a Rails application.&lt;/p&gt;

&lt;p&gt;Money-Rails greatly simplifies the whole process and provides helper methods that make working with money safer and more maintainable in the long run.&lt;/p&gt;

&lt;p&gt;Many other options are available to customize this for your Ruby on Rails app. Check out the full details in the &lt;a href="https://github.com/RubyMoney/money"&gt;&lt;code&gt;money&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/RubyMoney/money-rails"&gt;&lt;code&gt;money-rails&lt;/code&gt;&lt;/a&gt; guides.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/ruby-magic"&gt;subscribe to our Ruby Magic newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>An Introduction to Exceptions in Elixir</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Tue, 03 Oct 2023 11:00:00 +0000</pubDate>
      <link>https://forem.com/appsignal/an-introduction-to-exceptions-in-elixir-2kil</link>
      <guid>https://forem.com/appsignal/an-introduction-to-exceptions-in-elixir-2kil</guid>
      <description>&lt;p&gt;Exceptions are a core aspect of programming, and a way to signal when something goes wrong with a program. An exception could result from a simple error, or your program might crash because of underlying constraints. Exceptions are not necessarily bad, though — they are fundamental to any working application.&lt;/p&gt;

&lt;p&gt;Let’s see what our options are for handling exceptions in Elixir.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raising Exceptions in Elixir
&lt;/h2&gt;

&lt;p&gt;The Elixir (and Erlang) community is generally quite amenable to exceptions: “let it crash” is a common phrase. This is due, in part, to the excellent OTP primitives in Erlang/Elixir. The OTP primitives allow us to create supervisors that manage and restart processes (or a group of related processes) on failure.&lt;/p&gt;

&lt;p&gt;Exceptions can occur when something unexpected happens in your Elixir application. For example, division by zero raises an &lt;code&gt;ArithmeticError&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ArithmeticError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;arithmetic&lt;/span&gt; &lt;span class="ss"&gt;expression:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="ss"&gt;iex:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exceptions can also be raised manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"BOOM"&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;BOOM&lt;/span&gt;
    &lt;span class="ss"&gt;iex:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, &lt;code&gt;raise&lt;/code&gt; creates a &lt;code&gt;RuntimeError&lt;/code&gt;. You can also raise other errors by using &lt;a href="https://hexdocs.pm/elixir/1.14/Kernel.html#raise/2" rel="noopener noreferrer"&gt;&lt;code&gt;raise/2&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;ArgumentError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;message:&lt;/span&gt; &lt;span class="s2"&gt;"cannot divide by zero"&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ArgumentError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cannot&lt;/span&gt; &lt;span class="n"&gt;divide&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;zero&lt;/span&gt;
    &lt;span class="ss"&gt;iex:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="ss"&gt;iex:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A function call that doesn’t match a defined function raises an &lt;code&gt;ArgumentError&lt;/code&gt; by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FunctionClauseError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;clause&lt;/span&gt; &lt;span class="n"&gt;matching&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

    &lt;span class="no"&gt;The&lt;/span&gt; &lt;span class="n"&gt;following&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="n"&gt;were&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

        &lt;span class="c1"&gt;# 1&lt;/span&gt;
        &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="c1"&gt;# 2&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling Elixir Exceptions
&lt;/h2&gt;

&lt;p&gt;Elixir provides the &lt;code&gt;try&lt;/code&gt;-&lt;code&gt;rescue&lt;/code&gt; construct to handle exceptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"foo"&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="no"&gt;RuntimeError&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prints &lt;code&gt;%RuntimeError{message: "foo"}&lt;/code&gt; in the console but doesn’t crash anything. Use this when you want to recover from exceptions in Elixir. It is also possible to skip binding the variable if it is unnecessary. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"foo"&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt;
  &lt;span class="no"&gt;RuntimeError&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"something bad happened"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both of the above examples, we only &lt;code&gt;rescue&lt;/code&gt; &lt;code&gt;RuntimeError&lt;/code&gt;. If there is another error, it will still raise an exception. To rescue all exceptions raised inside the &lt;code&gt;try&lt;/code&gt; block, use the &lt;code&gt;rescue&lt;/code&gt; without an error type, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the above prints &lt;code&gt;%ArithmeticError{message: "bad argument in arithmetic expression"}&lt;/code&gt;. If you want to perform different actions based on different exceptions, just add more clauses to the rescue branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt;
  &lt;span class="no"&gt;RuntimeError&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Runtime Error"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;ArithmeticError&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Arithmetic Error"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;_e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Unknown error"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While rescuing all errors (without using a specific type) sounds tempting, it is a good practice to rely on specific exceptions because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can perform different recovery tasks for different exceptions.&lt;/li&gt;
&lt;li&gt;It saves you from future breaking changes or programming errors going unnoticed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, consider the below function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Config&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;parse!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt;
      &lt;span class="n"&gt;_e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;some:&lt;/span&gt; &lt;span class="s2"&gt;"default config"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reads and parses a config file, returning the result. When written, it uses a generic clause to rescue from missing file-related errors. Let’s say that a while later, the input file gets corrupted somehow (e.g., a simple missing &lt;code&gt;}&lt;/code&gt; or an extra &lt;code&gt;,&lt;/code&gt; in a JSON file), and now there are parsing errors. Our function will still work without raising any issues, and we will be left guessing why it doesn’t work even though there’s an existing file.&lt;/p&gt;

&lt;p&gt;Another common practice in the Elixir community is to use &lt;code&gt;ok&lt;/code&gt;/&lt;code&gt;error&lt;/code&gt; tuples to signal errors instead of raising exceptions (for both internal and external libraries). So, instead of returning a simple &lt;code&gt;result&lt;/code&gt; or raising an exception on an issue, a function in Elixir will return &lt;code&gt;{:ok, result}&lt;/code&gt; on success and &lt;code&gt;{:error, reason}&lt;/code&gt; on failure.&lt;/p&gt;

&lt;p&gt;This means that most of the time, a &lt;code&gt;case&lt;/code&gt; block will be preferable to try/rescue. For example, the above &lt;code&gt;File.read!&lt;/code&gt; can be replaced by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parse!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;some:&lt;/span&gt; &lt;span class="s2"&gt;"default config"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In practice, you should reach out for &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;raise&lt;/code&gt; only in exceptional cases, never as a means of control flow. This is quite different from some other popular languages like Ruby or Java, where unexpected operations usually raise an error, then handle control flow for cases like non-existent files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Re-raising Exceptions
&lt;/h2&gt;

&lt;p&gt;Sometimes, we just want to know that there is an exception but not rescue from it — for example, to log an exception before allowing the process to crash or to wrap the exception into something more useful/understandable to the user.&lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;reraise&lt;/code&gt; can be helpful, as it preserves an exception's existing stack trace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__STACKTRACE__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;reraise&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__STACKTRACE__&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we use the &lt;code&gt;__STACKTRACE__&lt;/code&gt; to retrieve the original trace of the exception, including its origin and the full call stack.&lt;/p&gt;

&lt;p&gt;In a real-world application, you might use this to report a metric / send an exception to a third-party exception tracking service, or log something informative to a third-party logging service. For example, &lt;a href="https://appsignal.com/users/sign_up" rel="noopener noreferrer"&gt;you might send telemetry data to AppSignal&lt;/a&gt; under these circumstances.&lt;/p&gt;

&lt;p&gt;In addition, it is also common practice to have custom exceptions for cases where unexpected things happen in libraries. &lt;code&gt;reraise/3&lt;/code&gt; can be useful here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;DivisionByZeroError&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;defexception&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt;
      &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="no"&gt;ArithmeticError&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;reraise&lt;/span&gt; &lt;span class="no"&gt;DivisionByZeroError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;__STACKTRACE__&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now using &lt;code&gt;Math.div(1, 0)&lt;/code&gt; will raise a &lt;code&gt;DivisionByZeroError&lt;/code&gt; instead of a generic &lt;code&gt;ArithmeticError&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rescue And Catch in Elixir
&lt;/h2&gt;

&lt;p&gt;In Elixir, &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;raise&lt;/code&gt;/&lt;code&gt;rescue&lt;/code&gt; and &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;throw&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; are different. &lt;code&gt;raise&lt;/code&gt; and &lt;code&gt;rescue&lt;/code&gt; are used for exception handling, whereas &lt;code&gt;throw&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; are used for control flow.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;throw&lt;/code&gt; stops code execution (much like a &lt;code&gt;return&lt;/code&gt; — the difference being that it bubbles up until a &lt;code&gt;catch&lt;/code&gt; is encountered). It is rarely needed and is only an escape hatch to be used when an API doesn’t provide an option to do something.&lt;/p&gt;

&lt;p&gt;For example, let's say that there’s an API that produces numbers and invokes a callback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Producer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(This is just an example. Assume that with the real API, it is much more expensive to produce each number, and it produces an infinite list of numbers.)&lt;/p&gt;

&lt;p&gt;We want to find the first number divisible by 13, since we don’t have any other apparent way of finding that number and stopping the production at that point. Let’s see how we can use &lt;code&gt;throw&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt;
  &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"First number divisible by 13 is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's worth stating that this is a bit of a contrived case, and most good APIs are designed in such a way that you never need to reach out for &lt;code&gt;throw&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  After and Else Blocks in Elixir
&lt;/h2&gt;

&lt;p&gt;You can use &lt;code&gt;after&lt;/code&gt; and &lt;code&gt;else&lt;/code&gt; blocks with all &lt;code&gt;try&lt;/code&gt; blocks. An &lt;code&gt;after&lt;/code&gt; block is called after processing all other blocks related to the &lt;code&gt;try&lt;/code&gt;, regardless of whether any of the blocks raised an error. This is useful for performing any required clean-up operations.&lt;/p&gt;

&lt;p&gt;For example, the below code creates a new producer and makes some results. If there’s an error during production, it will raise an exception. But the &lt;code&gt;after&lt;/code&gt; block ensures that the producer is still disposed of regardless.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;producer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;produce!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;after&lt;/span&gt;
  &lt;span class="no"&gt;Producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the other hand, an &lt;code&gt;else&lt;/code&gt; block is called only if the &lt;code&gt;try&lt;/code&gt; block is completed without raising an error. The &lt;code&gt;else&lt;/code&gt; block receives the &lt;code&gt;try&lt;/code&gt; block's result. The return value from the &lt;code&gt;else&lt;/code&gt; block is the final return value of the &lt;code&gt;try&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt;
  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:not_found&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="s2"&gt;"a"&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:a&lt;/span&gt;
  &lt;span class="n"&gt;_other&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:other&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, if the file exists with content &lt;code&gt;a&lt;/code&gt;, the result will be &lt;code&gt;:a&lt;/code&gt;. The result is &lt;code&gt;:not_found&lt;/code&gt; if the file doesn’t exist, and &lt;code&gt;:other&lt;/code&gt; if the content is anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exceptions and Processes
&lt;/h2&gt;

&lt;p&gt;No discussion about Elixir exceptions is complete without examining their impact on processes. Any unhandled exceptions cause a process to exit.&lt;/p&gt;

&lt;p&gt;With this in mind, let’s revisit the “let it crash” strategy. If we don’t handle an exception from a process, it will crash. This is good in a way because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Since all processes are separate from each other, an exception or unhandled crash from one process can never affect the state of another process.&lt;/li&gt;
&lt;li&gt;In most sophisticated Elixir applications, all the processes run under a supervision tree. So, an unexpected exit will restart the process (depending on the supervision strategy) and any linked processes with a clean slate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In most cases, intermittent issues will resolve themselves in the next run. This is much easier (and usually also cleaner) than handling each failure separately and performing a recovery step.&lt;/p&gt;

&lt;p&gt;If you want to learn more about supervisors, I suggest the &lt;a href="https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html" rel="noopener noreferrer"&gt;official Elixir Supervisor and Application guide&lt;/a&gt; as a great starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring Exceptions
&lt;/h2&gt;

&lt;p&gt;As we've seen, exceptions are a fundamental part of any application. Handling them is good, but sometimes, letting them crash a process is even better.&lt;/p&gt;

&lt;p&gt;But in all cases, it is better to monitor exceptions happening in the real world so that you can take action if there’s something concerning (for example, a developer error that crashes an app).&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://www.appsignal.com/elixir" rel="noopener noreferrer"&gt;AppSignal for Elixir&lt;/a&gt; can help. Once set up, it automatically records all errors and can also trigger alerts based on predefined conditions.&lt;/p&gt;

&lt;p&gt;Here's an example of an individual error you can get to from the "Errors" -&amp;gt; "Issue list" in AppSignal for debugging:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2023-06%2Ftrace-sample.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2023-06%2Ftrace-sample.png" alt="Trace sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://docs.appsignal.com/elixir/installation.html" rel="noopener noreferrer"&gt;AppSignal for Elixir installation guide&lt;/a&gt; to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we explored how errors are treated in Elixir and how to recover from them. We also saw that sometimes it is better to just let a process crash and be restarted through the supervisor than to manually perform recovery steps for all possible exceptions.&lt;/p&gt;

&lt;p&gt;Elixir’s API makes a clear distinction between functions that raise an exception (usually ending in &lt;code&gt;!&lt;/code&gt;) and functions that return a success/error tuple. If you are a library author, it is better to provide both options for users.&lt;/p&gt;

&lt;p&gt;Reach out for the tuple-based methods when you need to handle error cases separately. In Elixir, we rarely use &lt;code&gt;try&lt;/code&gt; blocks for control flow — the &lt;code&gt;!&lt;/code&gt; functions are for when we want a process to crash on unexpected events.&lt;/p&gt;

&lt;p&gt;Until next time, happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>An Introduction to Mocking Tools for Elixir</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Tue, 18 Apr 2023 11:09:36 +0000</pubDate>
      <link>https://forem.com/appsignal/an-introduction-to-mocking-tools-for-elixir-4ief</link>
      <guid>https://forem.com/appsignal/an-introduction-to-mocking-tools-for-elixir-4ief</guid>
      <description>&lt;p&gt;A well-written test suite is a big part of any successful application. But let's say you rely on an external dependency for some parts of your app (for example, an external API for fetching user information). It then becomes important to mock that dependency in the test suite to prevent external API calls during testing or to test specific behavior.&lt;/p&gt;

&lt;p&gt;Several frameworks help reduce the boilerplate and make mocking safe for Elixir tests. We will explore some of the major mocking tools available in this post.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Without Mocking Tools in Elixir
&lt;/h2&gt;

&lt;p&gt;Depending on the scope of your tests, you might not need to use any external mocking tools. You can use test stubs or roll your own server instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Stubs
&lt;/h3&gt;

&lt;p&gt;The simplest way to stub/mock out some parts from a function call is to pass around modules that do the actual work and use a different implementation during the tests.&lt;/p&gt;

&lt;p&gt;Let’s say you need to access the GitHub API to fetch a user’s profile with an implementation like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://api.github.com/users/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We know the implementation relies on HTTPoison to make actual calls to the GitHub API. To mock it during tests, we can update the implementation to pass around an &lt;code&gt;http_client&lt;/code&gt; and use a different one during tests.&lt;/p&gt;

&lt;p&gt;Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http_client&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;http_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://api.github.com/users/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="c1"&gt;#... handle results&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach aligns with the &lt;a href="https://www.infoworld.com/article/3136224/demystifying-the-law-of-demeter-principle.html"&gt;Law of Demeter&lt;/a&gt; — a module should only have limited knowledge of the objects (in this case, the HTTP client) it works on. This approach is nice because it decouples the &lt;code&gt;GithubAPI&lt;/code&gt; module from the HTTP client implementation.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;GithubAPI&lt;/code&gt; users can continue using it in the same way.&lt;br&gt;
But for unit-testing &lt;code&gt;GithubAPI&lt;/code&gt;, we can pass in our custom &lt;code&gt;http_client&lt;/code&gt; that returns just the results we need.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GithubAPITest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GithubHTTPClientUser&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://api.github.com/users/octocat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;status_code:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;body:&lt;/span&gt; &lt;span class="sx"&gt;~s&amp;lt;{"login": "octocat"}&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://api.github.com/users/unknown"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;message:&lt;/span&gt; &lt;span class="s2"&gt;"Not Found"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"can fetch a user"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;login:&lt;/span&gt; &lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GithubHTTPClientUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"handles errors when fetching a user"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;{}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"unknown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GithubHTTPClientUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works, and you have 100% test coverage! 🎉 But as you can already imagine, while this works well for small tests, it will become increasingly difficult to manage if our &lt;code&gt;GithubAPI&lt;/code&gt; class grows to include other features.&lt;/p&gt;

&lt;p&gt;Another similar strategy is to use application configuration instead of passing around the client modules. This is especially useful when you need to mock out the API from all the tests, even when this API is called from other internal modules.&lt;/p&gt;

&lt;p&gt;We can update our code to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# github_api.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@http_client&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:http_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;@http_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://api.github.com/users/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="c1"&gt;#... handle results&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# test/support/mock_github_http_client.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MockGithubHTTPClient&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# ... All mock implementations here&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# config/test.exs&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;http_client:&lt;/span&gt; &lt;span class="no"&gt;MockGithubHTTPClient&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The good thing is that you don’t need to worry about mocking out &lt;code&gt;GithubAPI&lt;/code&gt; calls in each test case by manually passing the HTTP client.&lt;/p&gt;

&lt;p&gt;This is especially important when the actual API calls are nested inside other functions. For example, if your application automatically fetches the user from GitHub after a new account is created, you don’t need to mock &lt;code&gt;GithubAPI&lt;/code&gt; everywhere you create new users.&lt;/p&gt;

&lt;p&gt;But it still has the same disadvantages as the previous strategy. Plus, the mocks must be generic enough to be used throughout the test suite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Roll Your Own Server
&lt;/h3&gt;

&lt;p&gt;This one is interesting. Since &lt;a href="https://github.com/elixir-plug/plug_cowboy"&gt;plug and cowboy&lt;/a&gt; make it really easy to roll out an HTTP server, instead of mocking out the HTTP Client, we can start our own server during tests and respond with stubs instead.&lt;/p&gt;

&lt;p&gt;If you want to learn more, check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/flatiron-labs/rolling-your-own-mock-server-for-testing-in-elixir-2cdb5ccdd1a0"&gt;Testing External Web Requests in Elixir? Roll Your Own Mock Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.appsignal.com/2021/06/22/how-to-test-websocket-clients-in-elixir-with-a-mock-server.html"&gt;How to Test WebSocket Clients in Elixir with a Mock Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the strategies discussed above, quite a bit of boilerplate is involved in setting up the tests.&lt;br&gt;
And if you need a way to validate that a specific function was called with specific arguments, you need to do additional work.&lt;/p&gt;

&lt;p&gt;If you just have a small external dependency that you need to mock out, this might work well for you. But if there are complex edge cases and branches that you need to test out, mocking tools can help simplify the complexity of writing and maintaining those mocks in the long run.&lt;/p&gt;
&lt;h2&gt;
  
  
  Elixir Mocking Tools
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Mock
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/jjh42/mock"&gt;Mock&lt;/a&gt; is the first result you will see when searching “Elixir Mock”, and is a wrapper around Erlang’s &lt;a href="https://github.com/eproxus/meck"&gt;meck&lt;/a&gt; that provides easy mocking macros for Elixir.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;Mock&lt;/code&gt;, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace any module at will during tests to change return values.&lt;/li&gt;
&lt;li&gt;Pass through to the original function.&lt;/li&gt;
&lt;li&gt;Validate calls to the mocked functions.&lt;/li&gt;
&lt;li&gt;Check the complete call history, including arguments and results for each call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a very powerful tool, and the macro &lt;a href="https://github.com/jjh42/mock#with_mock---Mocking-a-single-module"&gt;&lt;code&gt;with_mock&lt;/code&gt;&lt;/a&gt; makes mocking during tests really easy.&lt;/p&gt;

&lt;p&gt;Let’s see how we can rewrite our test case to validate &lt;code&gt;GithubAPI.fetch_user&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GithubAPITest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# This is important, Mock doesn't work with async tests!&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;async:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;

  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Mock&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"can fetch a user"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with_mock&lt;/span&gt; &lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;get:&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;_url&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;status_code:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;body:&lt;/span&gt; &lt;span class="sx"&gt;~s({"login": "octocat"})&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;login:&lt;/span&gt; &lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;assert_called&lt;/span&gt; &lt;span class="no"&gt;HTTPotion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://api.github.com/users/octocat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Very sleek. There's no need to define and pass boilerplate modules around or fiddle with the config just for tests. Our implementation is completely isolated from the test code and needs no special changes to fit the tests. And if we need to validate that a function was called with specific arguments, we can do that as well with &lt;code&gt;assert_called&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One of the major drawbacks of this strategy is that you cannot use it with &lt;code&gt;async&lt;/code&gt; tests. It doesn’t prevent you from using Mock inside asynchronous tests, so this can lead to hard-to-track flaky tests.&lt;/p&gt;

&lt;p&gt;In my opinion, Mock works well for certain types of tests.&lt;br&gt;
I usually find myself reaching for it when we need to mock external libraries that we have no control over. For example, let’s say we use an &lt;a href="https://github.com/edgurgel/tentacat"&gt;external library&lt;/a&gt; to fetch a user’s GitHub profile instead of our custom &lt;code&gt;GithubAPI&lt;/code&gt;. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;github_username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Tentacat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Tentacat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;github_username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;# ... create user&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;# ... handle error&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we dig into the library’s documentation/code, we can see that it uses HTTPoison to make the eventual request to the API. But we don’t want to — or have a way to — customize that client just for tests. Here, &lt;code&gt;with_mock&lt;/code&gt; can easily help mock out that call so that we don’t request the API.&lt;/p&gt;

&lt;p&gt;In fact, a much better approach, in this case, is to use &lt;code&gt;with_mock&lt;/code&gt; to simply mock out the &lt;code&gt;Tentacat.Users.find&lt;/code&gt; call altogether. That saves you from having to dig into the library's internal code (which can change with any update) and solely relying on mocking out its public interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mox
&lt;/h2&gt;

&lt;p&gt;We saw above how easy it is to mock some methods out and have our tests pass.&lt;br&gt;
We sprinkle these calls in a few places to mock &lt;code&gt;HTTPoison&lt;/code&gt;, and we are done.&lt;/p&gt;

&lt;p&gt;But what if we later decide that &lt;code&gt;HTTPoison&lt;/code&gt; isn’t fast enough and want to switch to another HTTP client implementation? As expected, all our tests will fail — we have to go back and fix them.&lt;br&gt;
Even worse, what if the API for &lt;code&gt;HTTPoison&lt;/code&gt; changes, but since we mocked it out, our tests never failed, and we pushed something that didn’t work to production?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dashbitco/mox"&gt;Mox&lt;/a&gt; helps get around these issues by ensuring explicit contracts.&lt;br&gt;
Read &lt;a href="https://dashbit.co/blog/mocks-and-explicit-contracts"&gt;Mocks and Explicit Contracts&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;Using our &lt;code&gt;GithubAPI&lt;/code&gt; example above, this is how we need to set up the tests with Mox.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mock the External Client
&lt;/h3&gt;

&lt;p&gt;We first convert our API client into a &lt;a href="https://hexdocs.pm/elixir/1.4.5/behaviours.html"&gt;&lt;code&gt;Behaviour&lt;/code&gt;&lt;/a&gt; to define the explicit contract the API client should follow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/my_app/github/api.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@callback&lt;/span&gt; &lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;impl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;impl&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GtihubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we define the API Client that makes the actual request to fetch the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/my_app/github/http.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@behaviour&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://api.github.com/users/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# Parse response here...&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# Handle error here...&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in our test helper, we define a mock &lt;code&gt;MyApp.GithubAPI.Mock&lt;/code&gt; for the API and set it in our application environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test/test_helper.exs&lt;/span&gt;
&lt;span class="no"&gt;Mox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;defmock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;for:&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can refactor the test case to use &lt;code&gt;Mox&lt;/code&gt; for mocking out the call to the external API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test/my_app/github/api_test.exs&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GithubAPITest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;async:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Mox&lt;/span&gt;

  &lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="ss"&gt;:verify_on_exit!&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"can fetch a user"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mock&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:fetch_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="s2"&gt;"octocat"&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;login:&lt;/span&gt; &lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;login:&lt;/span&gt; &lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are several interesting aspects to the above code. Let's break it down.&lt;/p&gt;

&lt;p&gt;First, we use the &lt;code&gt;expect&lt;/code&gt; function to define an expectation on the API. We expect a single call to &lt;code&gt;fetch_user&lt;/code&gt; with the argument &lt;code&gt;"octocat"&lt;/code&gt;, and we mock it to return a &lt;code&gt;{:ok, %Github.User{}}&lt;/code&gt; tuple.&lt;/p&gt;

&lt;p&gt;Now, when we call &lt;code&gt;GithubAPI.fetch_user/1&lt;/code&gt; in the test, it will reach for that mocked expectation instead of the default implementation. Thus, we can safely assert the result of the call without making calls to the actual API.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;verify_on_exit!&lt;/code&gt; function as &lt;code&gt;setup&lt;/code&gt; ensures that all expectations defined with &lt;code&gt;expect&lt;/code&gt; are fulfilled when a test case finishes. So if we define an expectation on &lt;code&gt;fetch_user&lt;/code&gt; and it isn't actually called (e.g., if the implementation changes later), we see the test fail.&lt;/p&gt;

&lt;p&gt;Finally, notice that we don't need to mark the test as non-async here. That’s because Mox supports mocking inside async tests. So you can define two completely different mocks in two test cases, and they will both pass, even if they run simultaneously.&lt;/p&gt;

&lt;p&gt;You can also define a global stub to avoid providing mocks in every test. This is useful if your client is being used in several places and you don’t want to explicitly define and validate expectations everywhere.&lt;/p&gt;

&lt;p&gt;To do this, just update your ExUnit case template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CaseTemplate&lt;/span&gt;

  &lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Mox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stub_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Stub&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And create a stub with some static results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Stub&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@behaviour&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;login:&lt;/span&gt; &lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every time you &lt;code&gt;use MyApp.Case&lt;/code&gt; in a test case, you don't need to manually mock calls to &lt;code&gt;GithubAPI&lt;/code&gt; — they will automatically be forwarded to the stubbed module. This works well when you have calls to the &lt;code&gt;GithubAPI&lt;/code&gt; that you will hit across several test suites. With a stub, you can be sure that such calls always return a specific and stable response without having to mock them out manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the External Client
&lt;/h3&gt;

&lt;p&gt;If you are following along closely, you will notice that we didn’t actually test the &lt;code&gt;MyApp.Github.HTTP&lt;/code&gt; module at all.&lt;br&gt;
Don’t worry, we won’t leave it untested.&lt;/p&gt;

&lt;p&gt;But the recommended way here is to do integration tests instead of using mocking at that level.&lt;/p&gt;

&lt;p&gt;We will also configure it so that these tests don’t run when you run the full test suite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test/my_app/github/http_test.exs&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;HTTPTest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;async:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

  &lt;span class="c1"&gt;# All tests will ping the API&lt;/span&gt;
  &lt;span class="nv"&gt;@moduletag&lt;/span&gt; &lt;span class="ss"&gt;:github_api&lt;/span&gt;

  &lt;span class="c1"&gt;# Write your tests here&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# test/test_helper.exs&lt;/span&gt;
&lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt; &lt;span class="ss"&gt;exclude:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:github_api&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to set up your CI pipeline to ensure that these tests run when required.&lt;/p&gt;

&lt;p&gt;For example, you can configure it to run on all pull requests targeting &lt;code&gt;main&lt;/code&gt; to avoid reaching the external API on every commit. You can also check that your CI pipeline runs before anything is merged to the main branch.&lt;/p&gt;

&lt;p&gt;To do this, use the &lt;code&gt;include&lt;/code&gt; command line flag when running &lt;code&gt;mix test&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;mix&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="n"&gt;github_api&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are several pros to the above strategy. You are now testing all parts of the application, including the calls to the external API (this part is not exactly dependent on Mox, but since we mocked out a significant part of our HTTP client, we must test it separately). We can also define global stubs, specific mocks, and expectations only when required, which makes most of our test suite very clean and concise.&lt;/p&gt;

&lt;p&gt;The major drawback is that it requires quite some setup — you need a new &lt;code&gt;behaviour&lt;/code&gt; with &lt;code&gt;@callbacks&lt;/code&gt; for each public method you want to mock out. You have to implement that &lt;code&gt;behaviour&lt;/code&gt; inside your module and finally set up &lt;code&gt;Mox&lt;/code&gt; to mock out that implementation during tests.&lt;/p&gt;

&lt;p&gt;And since we are now reaching the external API, the tests can be flaky, depending on the API's availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mimic
&lt;/h2&gt;

&lt;p&gt;If you are used to &lt;a href="https://github.com/freerange/mocha"&gt;Mocha&lt;/a&gt; for other languages, you can check out &lt;a href="https://github.com/edgurgel/mimic"&gt;Mimic&lt;/a&gt;. It lets you define stubs and expectations during tests by keeping track of the stubbed module in an ETS table.&lt;/p&gt;

&lt;p&gt;It also maintains separate mocks for each process, so you can continue using async tests. It’s a great alternative to &lt;a href="https://github.com/jjh42/mock"&gt;Mock&lt;/a&gt; — but that also means the same caveat applies: be careful about what you mock.&lt;/p&gt;

&lt;p&gt;Here’s how a sample test looks with Mimic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test_helper.exs&lt;/span&gt;
&lt;span class="no"&gt;Mmimc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# github_api_test.exs&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;GithubAPITest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;async:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Mimic&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"can fetch a user"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://api.github.com/users/octocat"&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HTTPoison&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;status_code:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;body:&lt;/span&gt; &lt;span class="sx"&gt;~s({"login": "octocat"})&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;login:&lt;/span&gt; &lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GithubAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"octocat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;expect/3&lt;/code&gt; automatically verifies that the function is called.&lt;br&gt;
And all &lt;code&gt;expect&lt;/code&gt; and &lt;code&gt;stub&lt;/code&gt; calls can be &lt;a href="https://github.com/edgurgel/mimic#using"&gt;chained&lt;/a&gt; to make up clear mocking code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Mocking Carefully for Your Elixir App
&lt;/h2&gt;

&lt;p&gt;Mocking is an important and necessary part of any test suite.&lt;br&gt;
But the thing to remember about mocking is that it is imperative to do it right.&lt;/p&gt;

&lt;p&gt;For example, it might be tempting to mock out an internal API to quickly simulate &lt;em&gt;something&lt;/em&gt; for a test. And yes, it works for quick unit tests. But then, someone else (or maybe you) comes along a while later and changes that &lt;em&gt;something&lt;/em&gt; that you mocked earlier.&lt;/p&gt;

&lt;p&gt;Your tests still pass since they use the mocked value. But in practice, the thing is now broken, and it will be caught much later in the feedback loop (or worse still, be shipped to the user as-is).&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;In this post, we explored several mocking strategies you can use in Elixir tests. The safest (and the one you should consider using first) is &lt;code&gt;Mox&lt;/code&gt;, as it forces mocked modules to have a defined behavior. Mox can therefore catch issues that arise from API changes during compilation.&lt;/p&gt;

&lt;p&gt;Reach out for &lt;code&gt;Mimic&lt;/code&gt; or &lt;code&gt;Mock&lt;/code&gt; when you need to mock external libraries you don't have any control over.&lt;/p&gt;

&lt;p&gt;Until next time, happy mocking!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>Database Performance Optimization and Scaling in Rails</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Wed, 04 Jan 2023 14:10:08 +0000</pubDate>
      <link>https://forem.com/appsignal/database-performance-optimization-and-scaling-in-rails-14m0</link>
      <guid>https://forem.com/appsignal/database-performance-optimization-and-scaling-in-rails-14m0</guid>
      <description>&lt;p&gt;Web applications usually rely heavily on databases, for the most part. And as applications grow, databases grow too. We keep scaling web servers and background workers to keep up with the heavy load. But eventually, the database needs to keep up with all the new connections from these processes.&lt;/p&gt;

&lt;p&gt;One way to tackle this is to grow a database with an app using vertical scaling. This means adding more CPU power and memory to the database server. But this is usually slow. You might have to copy all your data to the new server and then put the application down to change the database servers that it communicates with.&lt;/p&gt;

&lt;p&gt;This is also usually a one-way operation. You can't keep adding/removing CPU power or memory from the database server based on your load.&lt;/p&gt;

&lt;p&gt;This post will cover some alternative methods to fine-tune and scale a database under heavy load and improve the performance of your Rails app. We will focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Splitting schema and data between multiple databases&lt;/li&gt;
&lt;li&gt;Using read-only replica databases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get going!&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer: Scaling Isn't Always Needed
&lt;/h2&gt;

&lt;p&gt;As always, with any post about performance optimization and scaling, I would like to put up a standard disclaimer: &lt;strong&gt;make sure you have an issue before trying to solve it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, on one of our apps in production, we tackled scaling and optimization only when we started processing more than 3 million background jobs a day.&lt;/p&gt;

&lt;p&gt;This will, of course, be different for different apps. But usually, a good indicator of whether you need to optimize is if your database is always running at high CPU or memory usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Separate Database for Your Rails Application
&lt;/h2&gt;

&lt;p&gt;Sometimes, simply using a separate database server for a part of your app is a good solution. For example, your app might do two different things that don’t have a big overlap. Alternatively, maybe there's one very database-heavy feature, but it is only used rarely or by a small section of users. You should go for a separate database server if — and only if — there is a clear distinction between the parts of your app that will use different databases.&lt;/p&gt;

&lt;p&gt;For example, a separate database is useful when you're audit logging in a high-frequency app (or have other very high-volume data that isn't necessarily accessed frequently). Let's see how we can set this up.&lt;/p&gt;

&lt;p&gt;First, set up the &lt;code&gt;database.yml&lt;/code&gt; to configure the second database. Let’s call the second database &lt;code&gt;log&lt;/code&gt;. We'll add a &lt;code&gt;log_default&lt;/code&gt; entry for the secondary database with a common configuration across all environments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;log_default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;log_default&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DB_PORT"] || 5432 %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
  &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DB_USER"] || "postgres" %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DB_PASSWORD"] || "postgres" %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;migrations_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db/log_migrate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important bit here is the &lt;code&gt;migrations_paths&lt;/code&gt; option that tells Rails where to find migrations related to this database.&lt;/p&gt;

&lt;p&gt;Then, update &lt;code&gt;database.yml&lt;/code&gt; to configure access to the log database for &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, and &lt;code&gt;production&lt;/code&gt; environments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DB_NAME"] %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*log_default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["LOG_DB_NAME"] %&amp;gt;&lt;/span&gt;

&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my_app_test&lt;/span&gt;
  &lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*log_default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my_app_log_test&lt;/span&gt;

&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_URL"] %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
    &lt;span class="na"&gt;migrations_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db/log_migrate&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_LOG_URL"] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we move the configuration for each environment one level deeper. The configuration for our primary database lives inside the &lt;code&gt;primary&lt;/code&gt; key for each environment. The second database's configuration (that we call &lt;code&gt;log&lt;/code&gt;) lives inside the &lt;code&gt;log&lt;/code&gt; key. &lt;code&gt;primary&lt;/code&gt; is a special keyword that tells Rails to use this database as the default.&lt;/p&gt;

&lt;p&gt;The next step is to set up &lt;code&gt;ActiveRecord&lt;/code&gt; to use this new database. We first create a base class that establishes a connection to this database (instead of a primary one) using &lt;code&gt;establish_connection&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogRecord&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abstract_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;establish_connection&lt;/span&gt; &lt;span class="ss"&gt;:log&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, we inherit from &lt;code&gt;LogRecord&lt;/code&gt; instead of &lt;code&gt;ApplicationRecord&lt;/code&gt; for all the records that should access the &lt;code&gt;log&lt;/code&gt; DB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuditLog&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;LogRecord&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that you keep using the rails generators for generating models and migrations by appending the &lt;code&gt;--database log&lt;/code&gt; option to target the second database. The migration task now automatically migrates both databases, but if you need to only migrate one, you can use &lt;code&gt;db:migrate:primary&lt;/code&gt; or &lt;code&gt;db:migrate:log&lt;/code&gt; tasks.&lt;/p&gt;

&lt;p&gt;This works great if there is a clear distinction between two parts of the app. But what if you don’t have a clear idea of the database that's creating issues? There are still a couple of options left. Let's check them out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Read-Only Replicas for Rails
&lt;/h2&gt;

&lt;p&gt;Our second scaling option is to access data from read-only replicas while still writing to the primary database. This can improve performance for users who only browse parts of the app without performing any writing operations. Depending on your app's use case, this can be 80% of your users or 10% of them. So, evaluate the behavior of your users or your application use case before going down this route.&lt;/p&gt;

&lt;p&gt;For an app with a majority of read-only users (like Twitter, for example), you can gain huge improvements in performance. New read-only replicas can be added/removed at will without affecting the primary database, which opens up options for auto-scalability.&lt;/p&gt;

&lt;p&gt;Let's see how to set this up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up a Read-Only Replica
&lt;/h3&gt;

&lt;p&gt;As usual, we will start with modifications to the &lt;code&gt;database.yml&lt;/code&gt; config to include the replica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_URL"] %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;primary_replica&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_REPLICA_URL"] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, the &lt;code&gt;primary&lt;/code&gt; key is a special key indicating that this database is the default. We can use any other key for the replica database configuration. Let’s choose &lt;code&gt;primary_replica&lt;/code&gt; for sanity.&lt;/p&gt;

&lt;p&gt;Then update the &lt;code&gt;ApplicationRecord&lt;/code&gt; to configure a connection to multiple databases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationRecord&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abstract_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;

  &lt;span class="n"&gt;connects_to&lt;/span&gt; &lt;span class="ss"&gt;database: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;writing: :primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;reading: :primary_replica&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;production?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we add configuration for a &lt;code&gt;production&lt;/code&gt; environment only in the above example. If you want to, you can set it up for all environments, after modifying your development setup to support replicas.&lt;/p&gt;

&lt;p&gt;Finally, to use the read-only replica, you need to tell Rails when to use the primary database and when to use the replica. Rails provides a basic implementation for automatic role-switching based on the HTTP verb of the request out of the box. To enable it, add the following to your &lt;code&gt;production.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Use Read-Only Databases on GET requests&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;database_selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;delay: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;database_resolver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DatabaseSelector&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Resolver&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;database_resolver_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DatabaseSelector&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Resolver&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Session&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Rails to use the replica for all &lt;code&gt;GET&lt;/code&gt; or &lt;code&gt;HEAD&lt;/code&gt; requests and the primary one otherwise. Notice the option that sets the delay to two seconds? That tells Rails to keep using the primary database for &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;HEAD&lt;/code&gt; requests if it is within two seconds of a write request in the same session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gotchas
&lt;/h3&gt;

&lt;p&gt;Does all of this sound too simple? Well, we aren’t done yet. Depending on how your application is structured, you need to keep a few points in mind.&lt;/p&gt;

&lt;p&gt;Firstly, ensure you do not write anything in a read-only action like &lt;code&gt;index&lt;/code&gt; or &lt;code&gt;show&lt;/code&gt;. If there are legitimate reasons for writing during those operations, you can manually switch the connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connected_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;role: :writing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# Your code here&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good example where this can be useful is if you are managing sessions in a database. If you do that, make sure you use the &lt;code&gt;writing&lt;/code&gt; role. For example, you can override the &lt;code&gt;save_record&lt;/code&gt; method in your session with &lt;code&gt;authlogic&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserSession&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Authlogic&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="c1"&gt;# Your session configuration&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alternate_record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connected_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;role: :writing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another use case for automatic role-switching is when an app exposes a GraphQL API. All operations on a GraphQL API are &lt;code&gt;POST&lt;/code&gt;, but conventionally, all &lt;code&gt;queries&lt;/code&gt; are read-only, and &lt;code&gt;mutations&lt;/code&gt; are read-write. In this case, to allow Rails to select the correct database, we can use a custom tracer in the schema.&lt;/p&gt;

&lt;p&gt;First, create a tracer that switches roles based on the GraphQL document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Tracers&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseRoleTracer&lt;/span&gt;
    &lt;span class="no"&gt;EVENT_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"execute_multiplex"&lt;/span&gt;

    &lt;span class="c1"&gt;# Execute on read only database if the operation has only queries.&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;production?&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;EVENT_NAME&lt;/span&gt;

      &lt;span class="n"&gt;multiplex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:multiplex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connected_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;role: &lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multiplex&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

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

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multiplex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;multiplex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:query?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reading_role&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writing_role&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then use the &lt;code&gt;tracer&lt;/code&gt; in your GraphQL Schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAppSchema&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;GraphQL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;
  &lt;span class="n"&gt;tracer&lt;/span&gt; &lt;span class="no"&gt;Tracers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DatabaseRoleTracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

  &lt;span class="c1"&gt;# Your code here&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s get to the final alternative. What can you do if your application still has a huge load on your primary database? The answer: database sharding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Sharding in Your Rails Application
&lt;/h2&gt;

&lt;p&gt;This is the most complex of all the methods for scaling databases discussed in this post. So reach for it only if you need it. It will add considerable complexity to your application and needs to be done right to provide any real benefit.&lt;/p&gt;

&lt;p&gt;There are two strategies to shard your database:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Distribute different tables on different nodes (vertical sharding).&lt;/li&gt;
&lt;li&gt;Have the same schema across all nodes, but distribute data depending on certain parameters (horizontal sharding).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vertical sharding is similar to our “multiple databases” strategy in terms of setup and pros and cons, so we will not discuss it again.&lt;/p&gt;

&lt;p&gt;Let's discuss horizontal sharding and where it could be helpful.&lt;/p&gt;

&lt;p&gt;One example is when you have a SaaS platform where a lot of data is associated with each user, but there is no overlap between the data of two users. In this case, splitting the data across nodes based on the user's id is the most logical way to go. Every signed-in user will have to access only a single database, so we won't have to reach out to multiple databases at the same time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Horizontal Sharding
&lt;/h3&gt;

&lt;p&gt;Let’s start with the configuration inside &lt;code&gt;database.yml&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_URL"] %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;primary_replica&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_REPLICA_URL"] %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;primary_shard_one&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_SHARD_ONE_URL"] %&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;primary_shard_one_replica&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DATABASE_SHARD_ONE_REPLICA_URL"] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then modify the &lt;code&gt;ApplicationRecord&lt;/code&gt; to connect to different shards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;class ApplicationRecord &amp;lt; ActiveRecord::Base&lt;/span&gt;
  &lt;span class="s"&gt;self.abstract_class = &lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;

  &lt;span class="s"&gt;connects_to shards&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;writing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reading&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;primary_replica&lt;/span&gt; &lt;span class="pi"&gt;},&lt;/span&gt;
    &lt;span class="nv"&gt;shard_one&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;writing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;primary_shard_one&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reading&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;primary_shard_one_replica&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="s"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use the &lt;code&gt;shard&lt;/code&gt; option with &lt;a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionHandling.html#method-i-connected_to"&gt;&lt;code&gt;ActiveRecord::Base.connected_to&lt;/code&gt;&lt;/a&gt; to switch shards. Like the automatic database role selector, Rails also provides an automatic shard switcher that can be activated inside &lt;code&gt;production.rb&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shard_selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;lock: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shard_resolver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Tenant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;host: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;host&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;shard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;shard_resolver&lt;/code&gt; lambda is the most interesting part. The above implementation relies on the assumption that our application is accessed from different domains/subdomains and distinguishes between the shards. Modify it to fit your application needs (you might need to access cookies to identify a user before switching the shard).&lt;/p&gt;

&lt;p&gt;As with vertical scaling, this strategy is usually a one-way street. Once you shard a database, it is very hard to “un-shard” it (since several databases could have the same ids for different objects). But this lays down the foundation to really scale your app to millions or billions of users when fitting everything on the same server is not an option.&lt;/p&gt;

&lt;p&gt;If you want to read more about database sharding, see this &lt;a href="https://www.linode.com/docs/guides/sharded-database/"&gt;write-up by Linode&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure Your Rails Database Performance with AppSignal
&lt;/h2&gt;

&lt;p&gt;It can be tricky to keep an eye on the performance of your database without any other tools. Using AppSignal, you can easily track how your databases perform. See our &lt;a href="https://www.appsignal.com/ruby"&gt;AppSignal for Ruby page&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;You can also check out our post &lt;a href="https://blog.appsignal.com/2022/01/26/test-and-optimize-your-ruby-on-rails-database-performance.html"&gt;Test and Optimize Your Ruby on Rails Database Performance&lt;/a&gt; for more information on the metrics you can measure in AppSignal and how a dashboard might look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;In this post, we discussed three major strategies to scale your database servers horizontally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Splitting schema between multiple databases&lt;/li&gt;
&lt;li&gt;Using read-only replica databases&lt;/li&gt;
&lt;li&gt;Splitting data between multiple databases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All strategies have their pros and cons depending on your application use case and scale.&lt;/p&gt;

&lt;p&gt;Rails has really upped its database game in its last few releases. This post has shown how easy it is to set up a Rails app to use multiple databases.&lt;/p&gt;

&lt;p&gt;As always, if your application allows it, I suggest starting small with optimizations. The easiest optimization to start with is a read-only replica, then only move on when you need more scale.&lt;/p&gt;

&lt;p&gt;Happy scaling!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/ruby-magic"&gt;subscribe to our Ruby Magic newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Using Profiling in Elixir to Improve Performance</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Tue, 03 May 2022 10:52:22 +0000</pubDate>
      <link>https://forem.com/appsignal/using-profiling-in-elixir-to-improve-performance-35dn</link>
      <guid>https://forem.com/appsignal/using-profiling-in-elixir-to-improve-performance-35dn</guid>
      <description>&lt;p&gt;Elixir is all about performance. Say you have an app up and running with Elixir, but some parts aren't working as fast as you would like them to.&lt;/p&gt;

&lt;p&gt;That is where profiling comes in.&lt;/p&gt;

&lt;p&gt;Profiling tools usually walk you through the frequency and duration of function calls and where they spend their time.&lt;br&gt;
Erlang has impressive profile tooling available at its disposal.&lt;/p&gt;

&lt;p&gt;In this post, we will look into three profiling tools in Elixir: &lt;code&gt;cprof&lt;/code&gt;, &lt;code&gt;eprof&lt;/code&gt;, and &lt;code&gt;fprof&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Do I Need Profiling for My Elixir App?
&lt;/h2&gt;

&lt;p&gt;Firstly, I want to clarify that you may not need profiling at all. As Donald Knuth wrote: &lt;em&gt;'premature optimization is the root of all evil.'&lt;/em&gt; Some operations just cannot be optimized.&lt;/p&gt;

&lt;p&gt;For example, say you want to fetch something from your database. You issue a query and get a reply. This incurs a network round trip with some data. If you need all the data, the network round trip time cannot be optimized without moving your database closer to the app.&lt;/p&gt;

&lt;p&gt;With that out of the way, let's jump into profiling options.&lt;/p&gt;
&lt;h2&gt;
  
  
  Profiling with &lt;code&gt;cprof&lt;/code&gt; in Elixir
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cprof&lt;/code&gt; counts the number of times each function is invoked.&lt;br&gt;
It doesn't profile the time spent in those functions, so it comes with the least amount of overhead.&lt;/p&gt;

&lt;p&gt;Use it when you already have an estimate of your functions' runtimes. You'll see the frequency with which each function is invoked.&lt;/p&gt;

&lt;p&gt;Let's see how we can profile a Fibonacci number generator with &lt;code&gt;cprof&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://gist.github.com/pulkit110/c8223b7ebf4dc6cb918f440c45e201cd"&gt;follow along with the code&lt;/a&gt;. It uses the &lt;a href="https://rosettacode.org/wiki/Fibonacci_sequence#Elixir"&gt;Rosetta Code algorithm for Fibonacci sequence generation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Jump into an IEx session and run &lt;code&gt;cprof&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:cprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;19244&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:cprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;analyse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:fibonacci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:fibonacci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:"-fun.fibonacci/1-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:module_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:__info__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;]}&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:cprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;19266&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, start &lt;code&gt;cprof&lt;/code&gt;, run the code that you want to profile, and then call &lt;code&gt;:cprof.analyse/1&lt;/code&gt; to fetch the statistics for the given module. Several other options are available inside the &lt;a href="https://www.erlang.org/doc/man/cprof.html"&gt;&lt;code&gt;:cprof&lt;/code&gt; module&lt;/a&gt;, like pausing profiling with &lt;code&gt;:cprof.pause/0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can also use Mix's wrapper task &lt;a href="https://hexdocs.pm/mix/1.12/Mix.Tasks.Profile.Cprof.html"&gt;profile.cprof&lt;/a&gt; directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜ mix profile.cprof &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"FibonacciRosettaCode.list(10)"&lt;/span&gt;
                                                                     CNT
Total                                                                113
FibonacciRosettaCode                                                  77  &amp;lt;&lt;span class="nt"&gt;--&lt;/span&gt;
  FibonacciRosettaCode.fibonacci/3                                    54
  FibonacciRosettaCode.fibonacci/1                                    11
  FibonacciRosettaCode.&lt;span class="s2"&gt;"-fun.fibonacci/1-"&lt;/span&gt;/1                          11
  FibonacciRosettaCode.list/1                                          1
Enum                                                                  24  &amp;lt;&lt;span class="nt"&gt;--&lt;/span&gt;
  Enum.reduce_range/5                                                 12
  anonymous fn/3 &lt;span class="k"&gt;in &lt;/span&gt;Enum.map/2                                        11
  Enum.map/2                                                           1
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we can see that the function &lt;code&gt;fibonacci/3&lt;/code&gt; is called the most.&lt;/p&gt;

&lt;p&gt;So, if we can somehow decrease the number of calls to that function or optimize the code inside it, we could improve performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;eprof&lt;/code&gt; Profiling in Elixir
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cprof&lt;/code&gt; measures &lt;em&gt;counts&lt;/em&gt; while &lt;code&gt;eprof&lt;/code&gt; measures the &lt;em&gt;execution time&lt;/em&gt; (in addition to counts) spent inside each function.&lt;br&gt;
It has slightly more overhead than &lt;code&gt;cprof&lt;/code&gt;. Use &lt;code&gt;eprof&lt;/code&gt; when you want to find the most time-consuming functions.&lt;/p&gt;

&lt;p&gt;The usage is very similar to &lt;code&gt;cprof&lt;/code&gt;. You just need to &lt;code&gt;start&lt;/code&gt; the profiler, run the code you want to profile, and then call &lt;code&gt;analyze&lt;/code&gt; to fetch the results.&lt;/p&gt;

&lt;p&gt;Let's analyze the results from the mix task &lt;a href="https://hexdocs.pm/mix/1.12/Mix.Tasks.Profile.Eprof.html"&gt;&lt;code&gt;profile.eprof&lt;/code&gt;&lt;/a&gt; on our sample Fibonacci generator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜ mix profile.eprof &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"FibonacciRosettaCode.list(10)"&lt;/span&gt;
&lt;span class="c"&gt;#                                               CALLS     % TIME µS/CALL&lt;/span&gt;
Total                                             106 100.0   45    0.42
anonymous fn/0 &lt;span class="k"&gt;in&lt;/span&gt; :elixir_compiler_1.__FILE__/1     1  0.00    0    0.00
:lists.reverse/1                                    1  2.22    1    1.00
:lists.reverse/2                                    1  2.22    1    1.00
FibonacciRosettaCode.fibonacci/1                   11  4.44    2    0.18
Enum.map/2                                          1  4.44    2    2.00
Range.new/2                                         1  4.44    2    2.00
FibonacciRosettaCode.&lt;span class="s2"&gt;"-fun.fibonacci/1-"&lt;/span&gt;/1         11  8.89    4    0.36
FibonacciRosettaCode.list/1                         1  8.89    4    4.00
:erlang.apply/2                                     1  8.89    4    4.00
anonymous fn/3 &lt;span class="k"&gt;in &lt;/span&gt;Enum.map/2                       11 13.33    6    0.55
Enum.reduce_range/5                                12 13.33    6    0.50
FibonacciRosettaCode.fibonacci/3                   54 28.89   13    0.24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we can see that &lt;code&gt;fibonacci/3&lt;/code&gt; is again the most time-consuming part of our program, consuming 28.89% of the total execution time and 0.24µS per call.&lt;/p&gt;

&lt;p&gt;In addition, &lt;code&gt;eprof&lt;/code&gt; also allows us to profile function calls across different processes.&lt;/p&gt;

&lt;p&gt;The usage is very simple. Let's see an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="ss"&gt;:eprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_profiling&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;

&lt;span class="c1"&gt;# Do some work&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="ss"&gt;:eprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop_profiling&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="ss"&gt;:eprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to call &lt;code&gt;start_profiling/1&lt;/code&gt; with a list of processes to profile.&lt;/p&gt;

&lt;p&gt;By default, this also tracks any other processes started from a profiled process.&lt;/p&gt;

&lt;p&gt;When you are done, call &lt;code&gt;stop_profiling&lt;/code&gt; and run &lt;code&gt;analyze&lt;/code&gt; to get the results. They should look something like this, with an entry for each process and the percentage of time it was busy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;******&lt;/span&gt; Process &amp;lt;0.150.0&amp;gt;    &lt;span class="nt"&gt;--&lt;/span&gt; 37.26 % of profiled &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;***&lt;/span&gt;
FUNCTION                                                             CALLS        %   TIME  &lt;span class="o"&gt;[&lt;/span&gt;uS / CALLS]
&lt;span class="nt"&gt;--------&lt;/span&gt;                                                             &lt;span class="nt"&gt;-----&lt;/span&gt;  &lt;span class="nt"&gt;-------&lt;/span&gt;   &lt;span class="nt"&gt;----&lt;/span&gt;  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;----------&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
io:request/2                                                             3     0.00      0  &lt;span class="o"&gt;[&lt;/span&gt;      0.00]
...

&lt;span class="k"&gt;******&lt;/span&gt; Process &amp;lt;0.277.0&amp;gt;    &lt;span class="nt"&gt;--&lt;/span&gt; 0.05 % of profiled &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;***&lt;/span&gt;
FUNCTION                                             CALLS        %  TIME  &lt;span class="o"&gt;[&lt;/span&gt;uS / CALLS]
&lt;span class="nt"&gt;--------&lt;/span&gt;                                             &lt;span class="nt"&gt;-----&lt;/span&gt;  &lt;span class="nt"&gt;-------&lt;/span&gt;  &lt;span class="nt"&gt;----&lt;/span&gt;  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;----------&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="s1"&gt;'Elixir.FibonacciRosettaCode'&lt;/span&gt;:fibonacci/3                2     0.00     0  &lt;span class="o"&gt;[&lt;/span&gt;      0.00]
&lt;span class="s1"&gt;'Elixir.FibonacciRosettaCode'&lt;/span&gt;:fibonacci/1                3     3.03     1  &lt;span class="o"&gt;[&lt;/span&gt;      0.33]
&lt;span class="s1"&gt;'Elixir.FibonacciRosettaCode'&lt;/span&gt;:&lt;span class="s1"&gt;'-fun.fibonacci/1-'&lt;/span&gt;/1      3     3.03     1  &lt;span class="o"&gt;[&lt;/span&gt;      0.33]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The great thing about this is that you can run it in production systems by accessing the remote console. Just call &lt;code&gt;start_profiling/1&lt;/code&gt;, wait some time to process the requests or manually trigger some requests that you want to profile. Then call &lt;code&gt;stop_profiling&lt;/code&gt; followed by &lt;code&gt;analyze&lt;/code&gt; to get the results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;fprof&lt;/code&gt; in Elixir
&lt;/h2&gt;

&lt;p&gt;The final inbuilt tool that you can use to profile your applications is &lt;code&gt;fprof&lt;/code&gt;. It is a comprehensive profiling tool that generates a trace file containing timestamped entries for function calls, process-related events, and garbage collection data.&lt;/p&gt;

&lt;p&gt;You can then feed this trace file into other tools to visualize the results thoroughly or use &lt;code&gt;:fprof.analyse&lt;/code&gt; like above to fetch function counts and execution times.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;fprof&lt;/code&gt; through IEx is quite advanced compared to running &lt;code&gt;cprof&lt;/code&gt; and &lt;code&gt;eprof&lt;/code&gt;, but &lt;code&gt;fprof&lt;/code&gt; allows tracing multiple processes.&lt;/p&gt;

&lt;p&gt;Here is how you can generate a trace file for all processes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="ss"&gt;:fprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="ss"&gt;:fprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;:start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;procs:&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Do some work&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FibonacciRosettaCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="ss"&gt;:fprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:stop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;:fprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="ss"&gt;:fprof&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;analyse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;totals:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dest:&lt;/span&gt; &lt;span class="s1"&gt;'prof.analysis'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a comprehensive trace of everything that went on during the run with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CNT&lt;/code&gt; - the number of times a function is called&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACC&lt;/code&gt; - the accumulated time spent in the function, including other function calls&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OWN&lt;/code&gt; - the time the function spent to be executed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/pulkit110/10ad017e52ad25c6b0ad36199544fd8f"&gt;Here's the full file (50 MB)&lt;/a&gt;, if you are interested.&lt;/p&gt;

&lt;p&gt;Like &lt;code&gt;eprof&lt;/code&gt;, &lt;code&gt;fprof&lt;/code&gt; is a great tool for profiling applications in production directly. Note that this will significantly slow down the application, so be prepared for degraded performance during profiling and a huge trace file.&lt;/p&gt;

&lt;p&gt;So you have the data now. If you are feeling adventurous, you can start digging through the file and look for patterns.&lt;/p&gt;

&lt;p&gt;Or, you can use some tools to help visualize your data.&lt;br&gt;
A popular one is &lt;a href="https://github.com/isacssouza/erlgrind"&gt;&lt;code&gt;erlgrind&lt;/code&gt;&lt;/a&gt;. It converts the &lt;code&gt;fprof&lt;/code&gt; file to &lt;code&gt;cgrind&lt;/code&gt; format that you can open inside &lt;a href="https://kcachegrind.github.io/html/Home.html"&gt;&lt;code&gt;KCachegrind&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To convert the file, download &lt;code&gt;erlgrind&lt;/code&gt; and then run &lt;code&gt;src/erlgrind profile.fprof&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This will generate a &lt;code&gt;prof.cgrind&lt;/code&gt; file that you can open to see graphs like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QaPoA6Ux--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-04/cgrind.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QaPoA6Ux--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-04/cgrind.png" alt="qcachegrind graph" width="880" height="664"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Profile and Collect Metrics from Your Elixir App in Production
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;eprof&lt;/code&gt; and &lt;code&gt;fprof&lt;/code&gt; can assist with profiling your application in production, but there are a couple of additional tools worth mentioning — Phoenix Live Dashboard and AppSignal.&lt;/p&gt;
&lt;h3&gt;
  
  
  Phoenix Live Dashboard
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/phoenixframework/phoenix_live_dashboard"&gt;Phoenix's live dashboard&lt;/a&gt; can provide a great, quick overview of metrics. While not exactly a profiler, it shows OS data and metrics from telemetry events and processes, among other things.&lt;/p&gt;

&lt;p&gt;Here is an example of the dashboard in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2cETxCRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-04/phoenix-live-dashboard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2cETxCRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-04/phoenix-live-dashboard.png" alt="Phoenix Live Dashboard Screenshot" width="880" height="549"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  AppSignal
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://appsignal.com/"&gt;AppSignal&lt;/a&gt; is another great tool for collecting performance data (among other things). &lt;a href="https://docs.appsignal.com/elixir/installation/#installing-the-package"&gt;Adding AppSignal to an existing application&lt;/a&gt; takes a few seconds.&lt;/p&gt;

&lt;p&gt;Just install the &lt;code&gt;appsignal&lt;/code&gt; dependency and run the &lt;code&gt;appsignal.install&lt;/code&gt; mix task with an API key. It has a good set of default metric collection including the throughput and response times for the application. You could even set up &lt;a href="https://docs.appsignal.com/elixir/instrumentation/minutely-probes.html"&gt;minutely probes&lt;/a&gt; to track custom metrics.&lt;/p&gt;

&lt;p&gt;Here's an example of the AppSignal dashboard collecting data from a sample application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dl9lBtEJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-04/appsignal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dl9lBtEJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-04/appsignal.png" alt="AppSignal Screenshot" width="880" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are looking to collect data about specific blocks of code that you suspect are slow, AppSignal's instrumentation feature can help collect this data. Just wrap the suspected code inside &lt;code&gt;Appsignal.instrument/2&lt;/code&gt;, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;PageController&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:controller&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;custom_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"index.html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;custom_function&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Appsignal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"custom_function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="ss"&gt;:timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will show up on the AppSignal event graph tagged as &lt;code&gt;custom_function&lt;/code&gt;. You can then explore this event across multiple calls and make an informed decision about the need for optimization.&lt;/p&gt;

&lt;p&gt;Check out the full list of features in &lt;a href="https://docs.appsignal.com/elixir/"&gt;the AppSignal docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up: Measure Your Elixir App's Performance with Profiling
&lt;/h2&gt;

&lt;p&gt;In this post, we saw how inbuilt tools like &lt;code&gt;cprof&lt;/code&gt;, &lt;code&gt;eprof&lt;/code&gt;, and &lt;code&gt;fprof&lt;/code&gt; can help gather performance insights for your code, even during production.&lt;/p&gt;

&lt;p&gt;We also took a quick look at a couple of other tools to monitor and trace your applications: Phoenix Live Dashboard and AppSignal.&lt;/p&gt;

&lt;p&gt;Until next time, happy profiling!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>What's New in Rails 7</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Wed, 22 Dec 2021 12:01:21 +0000</pubDate>
      <link>https://forem.com/appsignal/whats-new-in-rails-7-1ck7</link>
      <guid>https://forem.com/appsignal/whats-new-in-rails-7-1ck7</guid>
      <description>&lt;p&gt;Rails 7 is just around the corner. We don't have a confirmed release date, but it is expected to be &lt;a href="https://twitter.com/rafaelfranca/status/1467974458015158273"&gt;available before Christmas&lt;/a&gt;, so not very long to go. The latest version as of this post's publication is &lt;code&gt;7.0.0.rc1&lt;/code&gt;, the first release candidate. Basecamp, HEY, Github, and Shopify have all been running the Rails 7 alpha in production, so we can expect even the release candidate to be pretty stable.&lt;/p&gt;

&lt;p&gt;In this post, we will look at some of the new features and changes that Rails 7 will bring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node and Webpack Not Required
&lt;/h2&gt;

&lt;p&gt;Yes, you read that right! JavaScript in Rails 7 will no longer require NodeJS or Webpack. And you can still use npm packages.&lt;/p&gt;

&lt;p&gt;Transpiling ES6 with Babel and bundling with Webpack require a lot of setup. While Rails supported it pretty well with the &lt;code&gt;Webpacker&lt;/code&gt; gem, this brought a lot of baggage, was hard to understand and make any changes to, especially while maintaining upgradability.&lt;/p&gt;

&lt;p&gt;Now, the default for new apps created with &lt;code&gt;rails new&lt;/code&gt; is to use import maps through the &lt;a href="https://github.com/rails/importmap-rails/"&gt;&lt;code&gt;importmaps-rails&lt;/code&gt; gem&lt;/a&gt;. Instead of writing a &lt;code&gt;package.json&lt;/code&gt; and installing dependencies with &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;, you use &lt;code&gt;./bin/importmap&lt;/code&gt; CLI to pin (or unpin or update) dependencies.&lt;/p&gt;

&lt;p&gt;For example, to install &lt;code&gt;date-fns&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./bin/importmap pin date-fns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add a line in &lt;code&gt;config/importmap.rb&lt;/code&gt; like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="s2"&gt;"date-fns"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"https://ga.jspm.io/npm:date-fns@2.27.0/esm/index.js"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your JavaScript code, you can continue using everything as you used to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formatDistance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subDays&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;date-fns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;formatDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;addSuffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;//=&amp;gt; "3 days ago"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing to keep in mind with this setup is that there is no transpiling between what you write and what the browser gets. For the most part, this is ok since all browsers that matter now support ES6 out of the box.&lt;/p&gt;

&lt;p&gt;But this also means that you won't be able to use TypeScript or JSX as they require transpilation to JS before use.&lt;/p&gt;

&lt;p&gt;So, if you want to use React with JSX, you still have to fall back to a different setup (using webpack/rollup/esbuild).&lt;/p&gt;

&lt;p&gt;Rails 7 can do this for you. All you need is one command with your chosen strategy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./bin/rails javascript:install:[esbuild|rollup|webpack]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Turbolinks and UJS Replaced by Turbo and Stimulus
&lt;/h2&gt;

&lt;p&gt;Applications generated with Rails 7 will get Turbo and Stimulus (from Hotwire) by default, instead of Turbolinks and UJS. &lt;a href="https://hotwired.dev/"&gt;Hotwire is a new approach that delivers fast updates to the DOM&lt;/a&gt; by sending HTML over the wire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encryption at Database Layer
&lt;/h2&gt;

&lt;p&gt;Rails 7 allows marking certain database fields as encrypted using the &lt;code&gt;encrypts&lt;/code&gt; method on &lt;code&gt;ActiveRecord::Base&lt;/code&gt;. This means that after an &lt;a href="https://edgeguides.rubyonrails.org/active_record_encryption.html#setup"&gt;initial setup&lt;/a&gt;, you can write code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;encrypts&lt;/span&gt; &lt;span class="ss"&gt;:text&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can continue using the encrypted attributes like you would any other attribute. Rails 7 will encrypt and decrypt it automatically between the database and your application.&lt;/p&gt;

&lt;p&gt;But this comes with a slight quirk: you cannot query the database by that field unless you pass a &lt;code&gt;deterministic: true&lt;/code&gt; option to the &lt;code&gt;encrypts&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;The deterministic mode is less secure than the default non-deterministic mode, so only use it for attributes you absolutely need to query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asynchronous Querying
&lt;/h2&gt;

&lt;p&gt;There is now a &lt;code&gt;load_async&lt;/code&gt; method that you can use when querying data to fetch results in the background. This is especially important when you need to load several un-related queries from a controller action. You can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;PostsController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="vi"&gt;@posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_async&lt;/span&gt;
    &lt;span class="vi"&gt;@categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_async&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will fire both queries in the background at the same time. So, if each query takes 200ms, the total time spent fetching the data is ~200ms instead of 400ms, if they are fetched serially.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zeitwerk Mode for Rails 7
&lt;/h2&gt;

&lt;p&gt;This is a breaking change for older applications that still run the classic loader. All Rails 7 applications must use Zeitwerk mode, but the switch is pretty easy. &lt;a href="https://edgeguides.rubyonrails.org/classic_to_zeitwerk_howto.html"&gt;Check out the full Zeitwerk upgrade guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Rails 7 Updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Retry Jobs Unlimited Times
&lt;/h3&gt;

&lt;p&gt;ActiveJob now allows passing &lt;code&gt;:unlimited&lt;/code&gt; as the &lt;code&gt;attempts&lt;/code&gt; parameter on &lt;code&gt;retry_on&lt;/code&gt;. Rails will continue to attempt the job without any maximum number of attempts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyJob&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveJob&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;retry_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;AlwaysRetryException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;attempts: :unlimited&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"KABOOM"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Named Variants
&lt;/h3&gt;

&lt;p&gt;You can now name variants on &lt;code&gt;ActiveStorage&lt;/code&gt; instead of specifying size on every access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_one_attached&lt;/span&gt; &lt;span class="ss"&gt;:avatar&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;attachable&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;attachable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;variant&lt;/span&gt; &lt;span class="ss"&gt;:thumb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;resize: &lt;/span&gt;&lt;span class="s2"&gt;"100x100"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;#Call avatar.variant(:thumb) to get a thumb variant of an avatar:&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= image_tag user.avatar.variant(:thumb) %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hash to HTML Attributes
&lt;/h3&gt;

&lt;p&gt;There is a new &lt;code&gt;tag.attributes&lt;/code&gt; method for use in views that translates a hash into HTML attributes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;type: :text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;aria: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;label: &lt;/span&gt;&lt;span class="s2"&gt;"Search"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will produce&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Search"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ruby &lt;code&gt;debug&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The new default for debugging has changed from &lt;code&gt;byebug&lt;/code&gt; to the &lt;a href="https://edgeguides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem"&gt;&lt;code&gt;debug&lt;/code&gt; gem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead of calling &lt;code&gt;byebug&lt;/code&gt;, you now need to call &lt;code&gt;debugger&lt;/code&gt; in the code to enter a debugging session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assert a Single Record with &lt;code&gt;sole&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;When querying records, you can now call &lt;code&gt;sole&lt;/code&gt; or &lt;code&gt;find_sole_by&lt;/code&gt; (instead of &lt;code&gt;first&lt;/code&gt; or &lt;code&gt;find_by&lt;/code&gt;) when you want to assert that the query should only match a single record.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"price = %?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;sole&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; ActiveRecord::RecordNotFound      (if no Product with given price)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Product ...&amp;gt;                    (if one Product with given price)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; ActiveRecord::SoleRecordExceeded  (if more than one Product with given price)&lt;/span&gt;

&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api_keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_sole_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;key: &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# as above&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check Presence/Absence of an Association
&lt;/h3&gt;

&lt;p&gt;We can now use &lt;code&gt;where.associated(:association)&lt;/code&gt; to check if an association is present on a record instead of joining and checking for the existence of an id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Before:&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:contact&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;contact_id: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# After:&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;associated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stream Generated Files from Controller Actions
&lt;/h3&gt;

&lt;p&gt;You can now use &lt;code&gt;send_stream&lt;/code&gt; inside a controller action to start streaming a file that is being generated on the fly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;send_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;filename: &lt;/span&gt;&lt;span class="s2"&gt;"subscribers.csv"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt; &lt;span class="s2"&gt;"email_address,updated_at&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="vi"&gt;@subscribers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;subscriber&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email_address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updated_at&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides an immediate (partial) response to the user so that they know something is happening and has an added benefit if you deploy on Heroku.&lt;/p&gt;

&lt;p&gt;Since the file will start streaming immediately, &lt;a href="https://devcenter.heroku.com/articles/request-timeout#long-polling-and-streaming-responses"&gt;Heroku will not terminate the connection&lt;/a&gt;. This means you don't need to resort to background jobs to generate one-off files that take longer than 30 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading to Rails 7
&lt;/h2&gt;

&lt;p&gt;As with previous versions of Rails, upgrading is simple. While we don't have an official upgrade guide yet, the steps will remain the same:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the Rails version number in the Gemfile (&lt;code&gt;7.0.0.rc1&lt;/code&gt; as of the publication date) and run &lt;code&gt;bundle update&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;bundle exec rails app:update&lt;/code&gt;. Follow the interactive CLI and add/replace/modify the files as required.&lt;/li&gt;
&lt;li&gt;Run your tests and verify everything works as expected.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;You can see the full list of bug fixes, features, and changes in the &lt;a href="https://edgeguides.rubyonrails.org/7_0_release_notes.html"&gt;Rails 7 release notes&lt;/a&gt;.&lt;br&gt;
These are not comprehensive at the moment, but we can expect them to be updated soon.&lt;/p&gt;

&lt;p&gt;If you are still running Rails 6 or lower, please note that with the final release of Rails 7, Rails 6.1 will enter the "security issues only" mode and will no longer receive bug fixes.&lt;/p&gt;

&lt;p&gt;This will also mark the EOL for Rails 5.2, as it will no longer receive any fixes.&lt;/p&gt;

&lt;p&gt;Have fun coding! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/ruby-magic"&gt;subscribe to our Ruby Magic newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Three Ways to Debug Code in Elixir</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Tue, 07 Dec 2021 13:11:29 +0000</pubDate>
      <link>https://forem.com/appsignal/three-ways-to-debug-code-in-elixir-56f</link>
      <guid>https://forem.com/appsignal/three-ways-to-debug-code-in-elixir-56f</guid>
      <description>&lt;p&gt;Elixir provides a very powerful suite of tools that devs can use to observe the behavior of their code and debug errors.&lt;/p&gt;

&lt;p&gt;There are several different strategies you can use to debug code in Elixir.&lt;/p&gt;

&lt;p&gt;While it is hard to produce a comprehensive list of all possible debugging methods, we will cover some of the most common methods in today's post.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The IO Module: &lt;code&gt;puts/2&lt;/code&gt; and &lt;code&gt;inspect/2&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Use the &lt;a href="https://hexdocs.pm/elixir/1.12/IO.html"&gt;&lt;code&gt;IO&lt;/code&gt; module&lt;/a&gt; for a quick and easy way to get some basic visibility into your code when debugging.&lt;/p&gt;

&lt;p&gt;You can print out log statements that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tell you where you are in executing code&lt;/li&gt;
&lt;li&gt;inspect structs and other entities&lt;/li&gt;
&lt;li&gt;display the function's arguments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;puts/2&lt;/code&gt; and &lt;code&gt;inspect/2&lt;/code&gt; are the most interesting to use when debugging. With these, it's easy to sprinkle a few good output messages throughout your code and then visualize what's happening.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;puts/2&lt;/code&gt; just prints out a string to the intended device (or &lt;code&gt;:stdio&lt;/code&gt; if you don't provide anything).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;inspect/2&lt;/code&gt; does something similar but writes out formatted output (e.g., pretty-printing maps, structs, and arrays).&lt;br&gt;
There are a couple of options to select the &lt;code&gt;width&lt;/code&gt; or a &lt;code&gt;label&lt;/code&gt; for the message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;foo:&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;label:&lt;/span&gt; &lt;span class="s2"&gt;"some map"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# some map: %{foo: :bar}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The great thing about &lt;code&gt;IO.inspect/2&lt;/code&gt; is that it returns the input, so it is easy to tap into long pipes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;label:&lt;/span&gt; &lt;span class="s2"&gt;"before"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;label:&lt;/span&gt; &lt;span class="s2"&gt;"after"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to this, if you need to create strings with embedded maps for the log messages, it is also possible to use &lt;code&gt;Kernel.inspect/2&lt;/code&gt; inside puts strings — like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"some map: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;foo:&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# some map: %{foo: :bar}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://hexdocs.pm/elixir/1.12/Inspect.Opts.html"&gt;&lt;code&gt;inspect&lt;/code&gt; method has a lot more options&lt;/a&gt; to customize your output.&lt;/p&gt;

&lt;p&gt;Finally, if you need to access a function's arguments quickly, it is possible to use &lt;code&gt;binding/1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Greeter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Prints [name: "John Doe"]&lt;/span&gt;
&lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Jane Doe"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Prints [name: "Jane Doe"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. IEx for Advanced Debugging Control
&lt;/h2&gt;

&lt;p&gt;If you need advanced control for debugging, the next tool you'll find useful is the interactive shell IEx. IEx lets you inspect and visualize the current state of your code, manually execute code, and examine the results.&lt;/p&gt;

&lt;p&gt;Just pop in &lt;code&gt;require IEx; IEx.pry&lt;/code&gt; anywhere in your code and then run it with &lt;code&gt;iex&lt;/code&gt;. So, if you are running a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standalone elixir file with &lt;code&gt;elixir fib.exs&lt;/code&gt;, use &lt;code&gt;iex -r fib.exs&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;Mix command like &lt;code&gt;mix run fib.exs&lt;/code&gt; or &lt;code&gt;mix phx.server&lt;/code&gt;, use &lt;code&gt;iex -S mix run fib.exs&lt;/code&gt; or &lt;code&gt;iex -S mix phx.server&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take a look at some of the things we can do with IEx.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Pry with IEx
&lt;/h3&gt;

&lt;p&gt;Let's see how debugging works with pry by looking at a &lt;a href="https://gist.github.com/pulkit110/cdf5341405d36a945faf6882b187c96d"&gt;buggy Fibonacci number generator&lt;/a&gt;. The code does not produce the expected result. Let's put a &lt;code&gt;require IEx; IEx.pry&lt;/code&gt; on line 9 (just after &lt;code&gt;fib2 = fib&lt;/code&gt;) and run it with &lt;code&gt;iex -r fib.exs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="no"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pry&lt;/span&gt; &lt;span class="c1"&gt;#PID&amp;lt;0.104.0&amp;gt; at Fib.number/1 (fib.exs:9)&lt;/span&gt;

    &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;fib1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fib2&lt;/span&gt;
    &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;fib2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;
    &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="kn"&gt;require&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pry&lt;/span&gt;
   &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;fib2&lt;/span&gt;

&lt;span class="no"&gt;Allow&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Yn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="no"&gt;Interactive&lt;/span&gt; &lt;span class="no"&gt;Elixir&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.12&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;press&lt;/span&gt; &lt;span class="no"&gt;Ctrl&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="no"&gt;C&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="k"&gt;exit&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="no"&gt;ENTER&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;_i:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;fib:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;fib1:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;fib2:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;n:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that it stops at the &lt;code&gt;IEx.pry()&lt;/code&gt; call. Then, we can inspect the values of the variables (or just use &lt;code&gt;binding&lt;/code&gt; to output all context).&lt;/p&gt;

&lt;p&gt;For the first iteration, everything looks good, &lt;code&gt;fib2&lt;/code&gt; updates to &lt;code&gt;1&lt;/code&gt;, and &lt;code&gt;fib1&lt;/code&gt; uses the previous value of &lt;code&gt;fib2&lt;/code&gt;, i.e., &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the next iteration, we expect &lt;code&gt;fib2&lt;/code&gt; to be &lt;code&gt;1 + 1 = 2&lt;/code&gt; and &lt;code&gt;fib1&lt;/code&gt; to be &lt;code&gt;1&lt;/code&gt;, and then &lt;code&gt;fib2&lt;/code&gt; to be &lt;code&gt;2 + 1 = 3&lt;/code&gt; and &lt;code&gt;fib1&lt;/code&gt; to be &lt;code&gt;2&lt;/code&gt;, and so on.&lt;/p&gt;

&lt;p&gt;So let's type &lt;code&gt;continue&lt;/code&gt; to go to the next &lt;code&gt;pry&lt;/code&gt; call and inspect the binding again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;continue&lt;/span&gt;
&lt;span class="no"&gt;Break&lt;/span&gt; &lt;span class="ss"&gt;reached:&lt;/span&gt; &lt;span class="no"&gt;Fib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;exs:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;fib1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fib2&lt;/span&gt;
    &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;fib2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;
    &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="kn"&gt;require&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pry&lt;/span&gt;
   &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;fib2&lt;/span&gt;

&lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;_i:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;fib:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;fib1:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;fib2:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;n:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we see that we are on the next iteration (&lt;code&gt;_i&lt;/code&gt; is &lt;code&gt;3&lt;/code&gt;), but apparently, the other variables do not change at all.&lt;br&gt;
So this is where our bug lies. Everything is immutable in Elixir, so assigning variables inside the anonymous function creates new variables rather than overriding the ones on the outer scope.&lt;/p&gt;

&lt;p&gt;We can now use this insight to fix our code.&lt;/p&gt;

&lt;p&gt;If you are curious, &lt;a href="https://gist.github.com/pulkit110/1c477da9e47dbc5fdb6df582b7999e59"&gt;see the fixed version of the Fibonacci number generator&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using Breakpoints with IEx
&lt;/h3&gt;

&lt;p&gt;In the previous section, we had to change the code to enter the pry session.&lt;br&gt;
IEx also provides a &lt;code&gt;break!&lt;/code&gt; function to set breakpoints without changing code.&lt;/p&gt;

&lt;p&gt;This is very important when you want to set breakpoints in parts of code that you don't own, coming from a library or even from Elixir standard modules.&lt;/p&gt;

&lt;p&gt;The only drawback is that this only works on compiled code, and you can only &lt;code&gt;break!&lt;/code&gt; at the start of the function, not on any arbitrary line.&lt;/p&gt;

&lt;p&gt;To use &lt;code&gt;break!&lt;/code&gt; with our Fibonacci example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;elixirc fib.ex &lt;span class="c"&gt;# This generates a beam file in your current dir&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.beam
Elixir.Fib.beam
&lt;span class="nv"&gt;$ &lt;/span&gt;iex            &lt;span class="c"&gt;# This will load all beam files in the current directory&lt;/span&gt;
iex&amp;gt; IEx.Helpers.break!&lt;span class="o"&gt;(&lt;/span&gt;Fib.number/1&lt;span class="o"&gt;)&lt;/span&gt;
iex&amp;gt; Fib.number&lt;span class="o"&gt;(&lt;/span&gt;5&lt;span class="o"&gt;)&lt;/span&gt;
Break reached: Fib.number/1 &lt;span class="o"&gt;(&lt;/span&gt;fib.ex:2&lt;span class="o"&gt;)&lt;/span&gt;

    1: defmodule Fib &lt;span class="k"&gt;do
    &lt;/span&gt;2:   def number&lt;span class="o"&gt;(&lt;/span&gt;n&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;3:     fib1 &lt;span class="o"&gt;=&lt;/span&gt; 0
    4:     fib2 &lt;span class="o"&gt;=&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bonus: IEx Tips and Tricks
&lt;/h3&gt;

&lt;p&gt;While we are on IEx, let us look at some general tips that can help you be more productive with it.&lt;/p&gt;

&lt;p&gt;The first, and possibly the most important, is to enable shell history if you use IEx a lot. You can then press &lt;code&gt;↑&lt;/code&gt; to get your last used commands or use &lt;code&gt;^ + R&lt;/code&gt; to reverse search the history of used commands.&lt;/p&gt;

&lt;p&gt;There are two ways you can enable shell history:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Enable each session by starting it with a flag:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;iex &lt;span class="nt"&gt;--erl&lt;/span&gt; &lt;span class="s2"&gt;"-kernel shell_history enabled"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable all sessions by setting the &lt;code&gt;ERL_AFLAGS&lt;/code&gt; environment on your shell. Depending on your terminal configuration, you will need to add the following (or its equivalent) to a startup script (like &lt;code&gt;~/.zshrc&lt;/code&gt;/&lt;code&gt;~/.bashrc&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ERL_AFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-kernel shell_history enabled"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second tip, which works on the recent version of Elixir (1.12+), means that you can use multi-line pipes directly in the shell. The pipe automatically gets the last evaluated statement's return value.&lt;/p&gt;

&lt;p&gt;So you can just copy and paste long pipes from your code directly in the IEx session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you often use modules in IEx, you can create a file called &lt;code&gt;.iex.exs&lt;/code&gt; from the directory used to access IEx. Alternatively, you can create a global file inside the home directory (&lt;code&gt;~/.iex/exs&lt;/code&gt;), and it will be evaluated every time you open an IEx session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Load another ".iex.exs" file&lt;/span&gt;
&lt;span class="n"&gt;import_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"~/.iex.exs"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Import some module from lib that may not yet have been defined&lt;/span&gt;
&lt;span class="n"&gt;import_if_available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Import Ecto.Query so that querying is always available in the shell&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Query&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, there are some cases when you might be using IEx and you make a typo (like an additional bracket or ") and the command cannot be terminated, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iex&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"abc"&lt;/span&gt;
...  &lt;span class="s2"&gt;"
...  ]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, you cannot use &lt;code&gt;^ + C&lt;/code&gt; or &lt;code&gt;^ + \&lt;/code&gt; as they would terminate the session, rather than just the command. To terminate the command immediately, start a new line with &lt;code&gt;#iex:break&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iex&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"abc"&lt;/span&gt;
...  &lt;span class="s2"&gt;"
...  ]
...  #iex:break
** (TokenMissingError) iex:1: incomplete expression
&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Visual Debugging
&lt;/h2&gt;

&lt;p&gt;In addition to the prying functionality provided by Elixir, there is also a more sophisticated Erlang debugger that you can use.&lt;/p&gt;

&lt;p&gt;While it works with a single compiled file like &lt;code&gt;IEx.break!&lt;/code&gt;, let's try using a file that is a part of a mix project with &lt;code&gt;iex -S mix&lt;/code&gt; this time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:debugger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;#PID&amp;lt;0.672.0&amp;gt;}&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Fib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Fib&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;break&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Fib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Fib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above will open the Erlang debugger and stop at the configured breakpoint.&lt;/p&gt;

&lt;p&gt;This provides a more traditional debugging approach where you can perform a single step or continue to the next breakpoint, evaluate expressions in the current context, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1F5LInzc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2021-11/debugging-code-in-elixir-erlang-debugger.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1F5LInzc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2021-11/debugging-code-in-elixir-erlang-debugger.png" alt="Erlang Debugger" width="880" height="759"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are using Visual Studio Code, the &lt;a href="https://marketplace.visualstudio.com/items?itemName=JakeBecker.elixir-ls"&gt;ElixirLS plugin&lt;/a&gt; supports in-editor breakpoints.&lt;br&gt;
There is also similar support in IntelliJ through the &lt;a href="https://github.com/KronicDeth/intellij-elixir#debugger"&gt;intellij-elixir plugin&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Debugging Elixir Processes
&lt;/h2&gt;

&lt;p&gt;A post on debugging Elixir code wouldn't be complete without also covering how to debug processes.&lt;/p&gt;

&lt;p&gt;While we can use the debugging methods we've already covered, a couple of other process-specific options are available.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using Trace to Debug Processes in Elixir
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;:sys.trace/2&lt;/code&gt; when you quickly want to see all the messages exchanged between a process and its state updates.&lt;br&gt;
We can use it to start/stop logging the process states and messages. Let's continue with the Fibonacci computer, but this time, &lt;a href="https://gist.github.com/pulkit110/e49fadea22e60758c26c5b6e81391ec1"&gt;wrapped inside a GenServer&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(3)&amp;gt; {:ok, pid} = GenServer.start_link(Fib, nil)
{:ok, #PID&amp;lt;0.1023.0&amp;gt;}
iex(4)&amp;gt; :sys.trace(pid, true)
:ok
iex(5)&amp;gt; GenServer.call(pid, {:get, 1})
*DBG* &amp;lt;0.1023.0&amp;gt; got call {get,1} from &amp;lt;0.1004.0&amp;gt;
*DBG* &amp;lt;0.1023.0&amp;gt; sent 1 to &amp;lt;0.1004.0&amp;gt;, new state #{0 =&amp;gt; 0,1 =&amp;gt; 1}
1
iex(6)&amp;gt; GenServer.call(pid, {:get, 2})
*DBG* &amp;lt;0.1023.0&amp;gt; got call {get,2} from &amp;lt;0.1004.0&amp;gt;
*DBG* &amp;lt;0.1023.0&amp;gt; sent nil to &amp;lt;0.1004.0&amp;gt;, new state #{0 =&amp;gt; 0,1 =&amp;gt; 1}
nil
iex(3)&amp;gt; GenServer.cast(pid, {:compute, 10})
*DBG* &amp;lt;0.1031.0&amp;gt; got cast {compute,10}
:ok
*DBG* &amp;lt;0.1031.0&amp;gt; new state #{0 =&amp;gt; 0,1 =&amp;gt; 1,2 =&amp;gt; 1,3 =&amp;gt; 2,4 =&amp;gt; 3,5 =&amp;gt; 5,6 =&amp;gt; 8,
                             7 =&amp;gt; 13,8 =&amp;gt; 21,9 =&amp;gt; 34,10 =&amp;gt; 55}
iex(4)&amp;gt; GenServer.call(pid, {:get, 2})
*DBG* &amp;lt;0.1031.0&amp;gt; got call {get,2} from &amp;lt;0.1029.0&amp;gt;
*DBG* &amp;lt;0.1031.0&amp;gt; sent 1 to &amp;lt;0.1029.0&amp;gt;, new state #{0 =&amp;gt; 0,1 =&amp;gt; 1,2 =&amp;gt; 1,
                                                   3 =&amp;gt; 2,4 =&amp;gt; 3,5 =&amp;gt; 5,
                                                   6 =&amp;gt; 8,7 =&amp;gt; 13,8 =&amp;gt; 21,
                                                   9 =&amp;gt; 34,10 =&amp;gt; 55}
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Debugging Processes with Observer in Elixir
&lt;/h3&gt;

&lt;p&gt;If you prefer a more visual approach, Erlang provides an &lt;code&gt;:observer&lt;/code&gt; that opens a user interface you can use to browse the Supervision Tree or check process states and messages.&lt;/p&gt;

&lt;p&gt;To access this, all you need is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:observer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While a full review of &lt;code&gt;:observer&lt;/code&gt; would take up a whole new post, here is a small demo of all that is possible:&lt;/p&gt;


  
  
  


&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;In this post, we've covered three common methods of debugging: using the IO module, IEx, and visual debugging. We've also touched on debugging Elixir processes using trace and observer.&lt;/p&gt;

&lt;p&gt;Elixir's powerful debugging tools are what make it such a compelling language choice for developers and businesses.&lt;/p&gt;

&lt;p&gt;Until next time, enjoy getting stuck into debugging code and processes in Elixir!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/category/elixir-alchemy.html#elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pulkit is a senior full-stack engineer and consultant. In his free time, he writes about his experiences on &lt;a href="https://pulkitgoyal.in"&gt;his blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>An Introduction to Pattern Matching in Ruby</title>
      <dc:creator>Pulkit Goyal</dc:creator>
      <pubDate>Wed, 04 Aug 2021 13:46:31 +0000</pubDate>
      <link>https://forem.com/appsignal/an-introduction-to-pattern-matching-in-ruby-1bci</link>
      <guid>https://forem.com/appsignal/an-introduction-to-pattern-matching-in-ruby-1bci</guid>
      <description>&lt;p&gt;Let's start with a brief discussion about pattern matching in Ruby, what it does, and how it can help improve code readability.&lt;/p&gt;

&lt;p&gt;If you are anything like me a few years ago, you might confuse it with pattern matching in Regex. Even a quick Google search of 'pattern matching' with no other context brings you content that's pretty close to that definition.&lt;/p&gt;

&lt;p&gt;Formally, pattern matching is the process of checking any data (be it a sequence of characters, a series of tokens, a tuple, or anything else) against other data.&lt;/p&gt;

&lt;p&gt;In terms of programming, depending on the capabilities of the language, this could mean any of the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matching against an expected data type&lt;/li&gt;
&lt;li&gt;Matching against an expected hash structure (e.g. presence of specific keys)&lt;/li&gt;
&lt;li&gt;Matching against an expected array length&lt;/li&gt;
&lt;li&gt;Assigning the matches (or a part of them) to some variables&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My first foray into pattern matching was through Elixir. Elixir has &lt;a href="https://elixir-lang.org/getting-started/pattern-matching.html"&gt;first class support&lt;/a&gt; for pattern matching, so much so that the &lt;code&gt;=&lt;/code&gt; operator is, in fact, the &lt;code&gt;match&lt;/code&gt; operator, rather than simple assignment.&lt;/p&gt;

&lt;p&gt;This means that in Elixir, the following is actually valid code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that in mind, let's look at the new pattern matching support for Ruby 2.7+ and how we can use it to make our code more readable, starting from today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ruby Pattern Matching with &lt;code&gt;case&lt;/code&gt;/&lt;code&gt;in&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Ruby supports pattern matching with a special &lt;code&gt;case&lt;/code&gt;/&lt;code&gt;in&lt;/code&gt; expression. The syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;pattern1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;pattern2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not to be confused with the &lt;code&gt;case&lt;/code&gt;/&lt;code&gt;when&lt;/code&gt; expression. &lt;code&gt;when&lt;/code&gt; and &lt;code&gt;in&lt;/code&gt; branches cannot be mixed in a single &lt;code&gt;case&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you do not provide an &lt;code&gt;else&lt;/code&gt; expression, any failing match will raise a &lt;code&gt;NoMatchingPatternError&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern Matching Arrays in Ruby
&lt;/h2&gt;

&lt;p&gt;Pattern matching can be used to match arrays to pre-required structures against data types, lengths or values.&lt;/p&gt;

&lt;p&gt;For example, all of the following are matches (note that only the first &lt;code&gt;in&lt;/code&gt; will be evaluated, as &lt;code&gt;case&lt;/code&gt; stops looking after the first match):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Three"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Three"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt; &lt;span class="c1"&gt;# because * is a spread operator that matches anything&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt; &lt;span class="c1"&gt;# and the value of the variable a is now 1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This type of pattern matching clause is very useful when you want to produce multiple signals from a method call.&lt;/p&gt;

&lt;p&gt;In the Elixir world, this is frequently used when performing operations that could have both an &lt;code&gt;:ok&lt;/code&gt; result and an &lt;code&gt;:error&lt;/code&gt; result, for example, inserted into a database.&lt;/p&gt;

&lt;p&gt;Here is how we can use it for better readability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:json&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
  &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:json&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Somewhere in your code, e.g. inside a global helper or your model base class (with a different name).&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pattern Matching Objects in Ruby
&lt;/h2&gt;

&lt;p&gt;You can also match objects in Ruby to enforce a specific structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;b: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt; &lt;span class="c1"&gt;# By default, all object matches are partial&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt; &lt;span class="c1"&gt;# and is same as {a: Integer}&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt; &lt;span class="c1"&gt;# and the value of variable a is now 1&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt; &lt;span class="c1"&gt;# and the value of variable a is now 1&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;b: &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt; &lt;span class="c1"&gt;# and the value of variable b is now 2&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"does not match"&lt;/span&gt; &lt;span class="c1"&gt;# This will match only if the object has a and no other keys&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works great when imposing strong rules for matching against any params.&lt;/p&gt;

&lt;p&gt;For example, if you are writing a fancy greeter, it could have the following (strongly opinionated) structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nb"&gt;hash&lt;/span&gt;
  &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;first_name: &lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_name: &lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Anonymous"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Anonymous"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;greet&lt;/span&gt; &lt;span class="c1"&gt;# Hello, Anonymous&lt;/span&gt;
&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Hello, John&lt;/span&gt;
&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;first_name: &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_name: &lt;/span&gt;&lt;span class="s2"&gt;"Doe"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Hello, John Doe&lt;/span&gt;
&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="s2"&gt;"Bonjour"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;first_name: &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_name: &lt;/span&gt;&lt;span class="s2"&gt;"Doe"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Bonjour, John Doe&lt;/span&gt;
&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;greeting: &lt;/span&gt;&lt;span class="s2"&gt;"Bonjour"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Bonjour, Anonymous&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Variable Binding and Pinning in Ruby
&lt;/h2&gt;

&lt;p&gt;As we have seen in some of the above examples, pattern matching is really useful in assigning part of the patterns to arbitrary variables.&lt;br&gt;
This is called variable binding, and there are several ways we can bind to a variable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;With a strong type match, e.g. &lt;code&gt;in [Integer =&amp;gt; a]&lt;/code&gt; or &lt;code&gt;in {a: Integer =&amp;gt; a}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Without the type specification, e.g. &lt;code&gt;in [a, 1, 2]&lt;/code&gt; or &lt;code&gt;in {a: a}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Without the variable name, which defaults to using the key name, e.g. &lt;code&gt;in {a:}&lt;/code&gt; will define a variable named &lt;code&gt;a&lt;/code&gt; with the value at key &lt;code&gt;a&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bind rest, e.g. &lt;code&gt;in [Integer, *rest]&lt;/code&gt; or &lt;code&gt;in {a: Integer, **rest}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How, then, can we match when we want to use an existing variable as a sub-pattern? This is when we can use variable &lt;em&gt;pinning&lt;/em&gt; with the &lt;code&gt;^&lt;/code&gt; (pin) operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;b: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;a: &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even use this when a variable is defined in a pattern itself, allowing you to write powerful patterns like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;billing_address: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:},&lt;/span&gt; &lt;span class="ss"&gt;shipping_address: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;city: &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"both billing and shipping are to the same city"&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"both billing and shipping must be to the same city"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One important quirk to mention with variable binding is that even if the pattern doesn't fully match, the variable will still have been bound.&lt;br&gt;
This can sometimes be useful.&lt;/p&gt;

&lt;p&gt;But, in most cases, this could also be a cause of subtle bugs — so make sure that you don't rely on shadowed variable values that have been used inside a match.&lt;br&gt;
For example, in the following, you would expect the city to be "Amsterdam", but it would instead be "Berlin":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Amsterdam"&lt;/span&gt;
&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;billing_address: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;city: &lt;/span&gt;&lt;span class="s2"&gt;"Berlin"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;shipping_address: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;city: &lt;/span&gt;&lt;span class="s2"&gt;"Zurich"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;billing_address: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:},&lt;/span&gt; &lt;span class="ss"&gt;shipping_address: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;city: &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"both billing and shipping are to the same city"&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"both billing and shipping must be to the same city"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="c1"&gt;# Berlin instead of Amsterdam&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Matching Ruby's Custom Classes
&lt;/h2&gt;

&lt;p&gt;You can implement some special methods to make custom classes pattern matching aware in Ruby.&lt;/p&gt;

&lt;p&gt;For example, to pattern match a user against his &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt;, we can define &lt;code&gt;deconstruct_keys&lt;/code&gt; on the class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deconstruct_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;first_name: &lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_name: &lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;first_name: &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Hey, John"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;keys&lt;/code&gt; argument to &lt;code&gt;deconstruct_keys&lt;/code&gt; contains the keys that have been requested in the pattern.&lt;br&gt;
This is a way for the receiver to provide only the required keys if computing all of them is expensive.&lt;/p&gt;

&lt;p&gt;In the same way as &lt;code&gt;deconstruct_keys&lt;/code&gt;, we could provide an implementation of &lt;code&gt;deconstruct&lt;/code&gt; to allow objects to be pattern matched as an array.&lt;br&gt;
For example, let's say we have a &lt;code&gt;Location&lt;/code&gt; class that has latitude and longitude. In addition to using &lt;code&gt;deconstruct_keys&lt;/code&gt; to provide latitude and longitude keys, we could expose an array in the form of &lt;code&gt;[latitude, longitude]&lt;/code&gt; as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Location&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deconstruct&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Float&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Float&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Guards for Complex Patterns
&lt;/h2&gt;

&lt;p&gt;If we have complex patterns that cannot be represented with regular pattern match operators, we can also use an &lt;code&gt;if&lt;/code&gt; (or &lt;code&gt;unless&lt;/code&gt;) statement to provide a guard for the match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="s2"&gt;"matches"&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="s2"&gt;"no match"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pattern Matching with &lt;code&gt;=&amp;gt;&lt;/code&gt;/&lt;code&gt;in&lt;/code&gt; Without &lt;code&gt;case&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If you are on Ruby 3+, you have access to even more pattern matching magic. Starting from Ruby 3, pattern matching can be done in a single line without a case statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Three"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="c1"&gt;# 1&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="c1"&gt;# 2&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt; &lt;span class="c1"&gt;# Three&lt;/span&gt;

&lt;span class="c1"&gt;# Same as above&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Three"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given that the above syntax does not have an &lt;code&gt;else&lt;/code&gt; clause, it is most useful when the data structure is known beforehand.&lt;/p&gt;

&lt;p&gt;As an example, this pattern could fit well inside a base controller that allows only admin users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AdminController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;AuthenticatedController&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:verify_admin&lt;/span&gt;

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

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify_admin&lt;/span&gt;
    &lt;span class="no"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;role: :admin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;NoMatchingPatternError&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;NotAllowedError&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pattern Matching in Ruby: Watch This Space
&lt;/h2&gt;

&lt;p&gt;At first, pattern matching can feel a bit strange to grasp.&lt;br&gt;
To some, it might feel like glorified object/array deconstruction.&lt;/p&gt;

&lt;p&gt;But if the popularity of Elixir is any indication, pattern matching is a great tool to have in your arsenal.&lt;br&gt;
Having first-hand experience using it on Elixir, I can confirm that it is hard to live without once you get used to it.&lt;/p&gt;

&lt;p&gt;If you are on Ruby 2.7, pattern matching (with &lt;code&gt;case&lt;/code&gt;/&lt;code&gt;in&lt;/code&gt;) is still experimental. With Ruby 3, &lt;code&gt;case&lt;/code&gt;/&lt;code&gt;in&lt;/code&gt; has moved to stable while the newly introduced single-line pattern matching expressions are experimental.&lt;br&gt;
Warnings can be turned off with &lt;code&gt;Warning[:experimental] = false&lt;/code&gt; in code or &lt;code&gt;-W:no-experimental&lt;/code&gt; command-line key.&lt;/p&gt;

&lt;p&gt;Even though pattern matching in Ruby is still in its early stages, I hope you've found this introduction useful and that you're as excited as I am about future developments to come!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you’d like to read Ruby Magic posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/#ruby-magic"&gt;subscribe to our Ruby Magic newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Our guest author Pulkit is a senior full-stack engineer and consultant. In his free time, he writes about his experiences on &lt;a href="https://pulkitgoyal.in/"&gt;his blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
